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!
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):
40 * * decimation=<1|2|4>
44 * * [volume|bass|treble|balance]
47 * - LifeView FlyTV Prime 34FM (SAA7134 based) with driver from Ivan Uskov
48 * Partially works with:
49 * - ATI 9200 VIVO based card
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
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.
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
78 #include "libmpcodecs/img_format.h"
79 #include "libaf/af_format.h"
81 #include "osdep/timer.h"
86 #include "frequencies.h"
89 #include "tvi_dshow.h"
91 static tvi_handle_t
*tvi_init_dshow(tv_param_t
* tv_param
);
94 *---------------------------------------------------------------------------------------
98 *---------------------------------------------------------------------------------------
101 information about this file
103 const tvi_info_t tvi_info_dshow
= {
107 "Vladimir Voroshilov",
108 "Very experimental!! Use with caution"
113 ringbuffer related info
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
;
137 grabber_ringbuffer_t
*pbuf
;
141 Chain related structure
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
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
202 country table entry structure (for loading freq table stored in kstvtuner.ax
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
214 information about image formats
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
225 *---------------------------------------------------------------------------------------
227 * Methods forward declaration
229 *---------------------------------------------------------------------------------------
231 static HRESULT
init_ringbuffer(grabber_ringbuffer_t
* rb
, int buffersize
,
233 static HRESULT
show_filter_info(IBaseFilter
* pFilter
);
235 //defined in current MinGW release
236 HRESULT STDCALL
GetRunningObjectTable(DWORD
, IRunningObjectTable
**);
237 HRESULT STDCALL
CreateItemMoniker(LPCOLESTR
, LPCOLESTR
, IMoniker
**);
239 static CSampleGrabberCB
*CSampleGrabberCB_Create(grabber_ringbuffer_t
*
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 {
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" },
286 static const struct {
289 } tv_chanlist2country
[]={
301 //directshow table uses eastern europe freq table for russia
303 //directshow table uses western europe freq table for germany
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 {
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);
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);
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
;
468 prop
.cbBuffer
= pWF
->nAvgBytesPerSec
/nDiv
;
471 prop
.cbBuffer
+= pWF
->nBlockAlign
- 1;
472 prop
.cbBuffer
-= prop
.cbBuffer
% pWF
->nBlockAlign
;
476 hr
=OLE_QUERYINTERFACE(pOutPin
,IID_IAMBufferNegotiation
,pBN
);
478 mp_msg(MSGT_TV
,MSGL_DBG2
,"tvi_dshow: pOutPin->QueryInterface(IID_IAMBufferNegotiation) Error: 0x%x\n",(unsigned int)hr
);
480 hr
=OLE_CALL_ARGS(pBN
,SuggestAllocatorProperties
,&prop
);
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
);
487 mp_msg(MSGT_TV
,MSGL_DBG2
,"tvi_dshow: pInPin->QueryInterface(IID_IAMBufferNegotiation) Error: 0x%x",(unsigned int)hr
);
489 hr
=OLE_CALL_ARGS(pBN
,SuggestAllocatorProperties
,&prop
);
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
)
509 /// CSampleGrabberCD IUnknown interface methods implementation
510 static long STDCALL
CSampleGrabberCB_QueryInterface(ISampleGrabberCB
*
515 CSampleGrabberCB
*me
= (CSampleGrabberCB
*) This
;
518 Debug
printf("CSampleGrabberCB_QueryInterface(%p) called\n", This
);
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
);
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
,
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
);
551 HRESULT STDCALL
CSampleGrabberCB_BufferCB(ISampleGrabberCB
* This
,
553 BYTE
* pBuffer
, long lBufferLen
)
555 CSampleGrabberCB
*this = (CSampleGrabberCB
*) This
;
556 grabber_ringbuffer_t
*rb
= this->pbuf
;
561 if (!rb
->ringbuffer
) {
562 rb
->buffersize
/= lBufferLen
;
563 if (init_ringbuffer(rb
, rb
->buffersize
, lBufferLen
) != S_OK
)
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
;
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
;
579 LeaveCriticalSection(rb
->pMutex
);
584 /// wrapper. directshow does the same when BufferCB callback is requested
585 HRESULT STDCALL
CSampleGrabberCB_SampleCB(ISampleGrabberCB
* This
,
587 LPMEDIASAMPLE pSample
)
591 long long tStart
,tEnd
;
593 grabber_ringbuffer_t
*rb
= ((CSampleGrabberCB
*)This
)->pbuf
;
595 len
=OLE_CALL(pSample
,GetSize
);
597 hr
=OLE_CALL_ARGS(pSample
,GetTime
,&tStart
,&tEnd
);
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
);
606 hr
=CSampleGrabberCB_BufferCB(This
,1e-7*tStart
,buf
,len
);
611 /// main grabbing routine
612 static CSampleGrabberCB
*CSampleGrabberCB_Create(grabber_ringbuffer_t
*
615 CSampleGrabberCB
*This
= malloc(sizeof(CSampleGrabberCB
));
619 This
->lpVtbl
= malloc(sizeof(ISampleGrabberVtbl
));
621 CSampleGrabberCB_Destroy(This
);
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
;
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
)
652 IRunningObjectTable
*pROT
;
656 if (FAILED(GetRunningObjectTable(0, &pROT
))) {
659 wsprintfW(wsz
, L
"FilterGraph %08x pid %08x", (DWORD_PTR
) pUnkGraph
,
660 GetCurrentProcessId());
661 hr
= CreateItemMoniker(L
"!", wsz
, &pMoniker
);
663 hr
= OLE_CALL_ARGS(pROT
, Register
, ROTFLAGS_REGISTRATIONKEEPSALIVE
,
664 pUnkGraph
, pMoniker
, pdwRegister
);
665 OLE_RELEASE_SAFE(pMoniker
);
667 OLE_RELEASE_SAFE(pROT
);
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
)
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
;
714 DeleteCriticalSection(rb
->pMutex
);
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
,
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 *));
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));
766 destroy_ringbuffer(rb
);
767 return E_OUTOFMEMORY
;
773 rb
->pMutex
= (CRITICAL_SECTION
*) malloc(sizeof(CRITICAL_SECTION
));
775 destroy_ringbuffer(rb
);
776 return E_OUTOFMEMORY
;
778 InitializeCriticalSection(rb
->pMutex
);
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
797 * Caller should not free returned pointer
799 static char *physcon2str(const long lPhysicalType
)
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
;
809 * \brief converts MPlayer's chanlist to system country code.
811 * \param chanlist MPlayer's chanlist name
813 * \return system country code
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).
820 * Resolve trouble with cable channels (DirectShow's tuners must be switched between broadcast and cable channels modes.
822 static int chanlist2country(char *chanlist
)
825 for(i
=0; tv_chanlist2country
[i
].chanlist_name
; i
++)
826 if (!strcmp(chanlist
, tv_chanlist2country
[i
].chanlist_name
))
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
)
846 snprintf(szRCDATA
, 10, "#%d", (int)RT_RCDATA
);
847 snprintf(szName
, 10, "#%d", index
);
849 hRes
= FindResource(hDLL
, szName
, szRCDATA
);
853 hTable
= LoadResource(hDLL
, hRes
);
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
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
,
883 TRCCountryList
*pCountryList
;
886 mp_msg(MSGT_TV
, MSGL_DBG4
, "tvi_dshow: load_freq_table called %d (%d)\n",nCountry
,nInputType
);
887 /* ASSERT(sizeof(TRCCountryList)==10); // need properly aligned structure */
889 if (!pplFreqTable
|| !pnFirst
|| !pnLen
)
894 hDLL
= LoadLibrary("kstvtune.ax");
898 pCountryList
= GetRC(hDLL
, 9999);
903 for (i
= 0; pCountryList
[i
].CountryCode
!= 0; i
++)
904 if (pCountryList
[i
].CountryCode
== nCountry
)
906 if (pCountryList
[i
].CountryCode
== 0) {
910 if (nInputType
== TunerInputCable
)
911 index
= pCountryList
[i
].CableFreqTable
;
913 index
= pCountryList
[i
].BroadcastFreqTable
;
915 plFreqTable
= GetRC(hDLL
, index
); //First element is number of first channel, second - number of last channel
920 *pnFirst
= plFreqTable
[0];
921 *pnLen
= (int) (plFreqTable
[1] - plFreqTable
[0] + 1);
922 *pplFreqTable
= (long *) malloc((*pnLen
) * sizeof(long));
923 if (!*pplFreqTable
) {
927 for (i
= 0; i
< *pnLen
; i
++) {
928 (*pplFreqTable
)[i
] = plFreqTable
[i
+ 2];
935 * \brief tunes to given frequency through IKsPropertySet call
937 * \param pTVTuner IAMTVTuner interface of capture device
938 * \param lFreq frequency to tune (in Hz)
940 * \return S_OK success
941 * \return apropriate error code otherwise
944 * Due to either bug in driver or error in following code calll to IKsProperty::Set
945 * in this methods always fail with error 0x8007007a.
947 * \todo test code on other machines and an error
949 static HRESULT
set_frequency_direct(IAMTVTuner
* pTVTuner
, long lFreq
)
952 DWORD dwSupported
= 0;
954 KSPROPERTY_TUNER_MODE_CAPS_S mode_caps
;
955 KSPROPERTY_TUNER_FREQUENCY_S frequency
;
956 IKsPropertySet
*pKSProp
;
958 mp_msg(MSGT_TV
, MSGL_DBG4
, "tvi_dshow: set_frequency_direct called\n");
960 memset(&mode_caps
, 0, sizeof(mode_caps
));
961 memset(&frequency
, 0, sizeof(frequency
));
963 hr
= OLE_QUERYINTERFACE(pTVTuner
, IID_IKsPropertySet
, pKSProp
);
965 return hr
; //no IKsPropertySet interface
967 mode_caps
.Mode
= AMTUNER_MODE_TV
;
968 hr
= OLE_CALL_ARGS(pKSProp
, QuerySupported
, &PROPSETID_TUNER
,
969 KSPROPERTY_TUNER_MODE_CAPS
, &dwSupported
);
971 OLE_RELEASE_SAFE(pKSProp
);
975 if (!dwSupported
& KSPROPERTY_SUPPORT_GET
) {
976 OLE_RELEASE_SAFE(pKSProp
);
977 return E_FAIL
; //PROPSETID_TINER not supported
980 hr
= OLE_CALL_ARGS(pKSProp
, Get
, &PROPSETID_TUNER
,
981 KSPROPERTY_TUNER_MODE_CAPS
,
982 INSTANCEDATA_OF_PROPERTY_PTR(&mode_caps
),
983 INSTANCEDATA_OF_PROPERTY_SIZE(mode_caps
),
984 &mode_caps
, sizeof(mode_caps
), &cbBytes
);
986 frequency
.Frequency
= lFreq
;
988 if (mode_caps
.Strategy
== KS_TUNER_STRATEGY_DRIVER_TUNES
)
989 frequency
.TuningFlags
= KS_TUNER_TUNING_FINE
;
991 frequency
.TuningFlags
= KS_TUNER_TUNING_EXACT
;
993 if (lFreq
< mode_caps
.MinFrequency
|| lFreq
> mode_caps
.MaxFrequency
) {
994 OLE_RELEASE_SAFE(pKSProp
);
998 hr
= OLE_CALL_ARGS(pKSProp
, Set
, &PROPSETID_TUNER
,
999 KSPROPERTY_TUNER_FREQUENCY
,
1000 INSTANCEDATA_OF_PROPERTY_PTR(&frequency
),
1001 INSTANCEDATA_OF_PROPERTY_SIZE(frequency
),
1002 &frequency
, sizeof(frequency
));
1004 OLE_RELEASE_SAFE(pKSProp
);
1008 OLE_RELEASE_SAFE(pKSProp
);
1014 * \brief find channel with nearest frequency and set it
1016 * \param priv driver's private data
1017 * \param lFreq frequency in Hz
1019 * \return S_OK if success
1020 * \return E_FAIL if error occured
1022 static HRESULT
set_nearest_freq(priv_t
* priv
, long lFreq
)
1028 TunerInputType tunerInput
;
1031 mp_msg(MSGT_TV
, MSGL_DBG4
, "tvi_dshow: set_nearest_freq called\n");
1032 if(priv
->freq_table_len
== -1 && !priv
->freq_table
) {
1034 hr
= OLE_CALL_ARGS(priv
->pTVTuner
, get_ConnectInput
, &lInput
);
1035 if(FAILED(hr
)){ //Falling back to 0
1039 hr
= OLE_CALL_ARGS(priv
->pTVTuner
, get_InputType
, lInput
, &tunerInput
);
1041 if (load_freq_table(chanlist2country(priv
->tv_param
->chanlist
), tunerInput
, &(priv
->freq_table
), &(priv
->freq_table_len
), &(priv
->first_channel
)) != S_OK
) {//FIXME
1042 priv
->freq_table_len
=0;
1043 priv
->freq_table
=NULL
;
1044 mp_msg(MSGT_TV
, MSGL_ERR
, MSGTR_TVI_DS_UnableExtractFreqTable
);
1047 mp_msg(MSGT_TV
, MSGL_V
, MSGTR_TVI_DS_FreqTableLoaded
, tunerInput
== TunerInputAntenna
? "broadcast" : "cable",
1048 chanlist2country(priv
->tv_param
->chanlist
), priv
->freq_table_len
);
1051 if (priv
->freq_table_len
<= 0)
1054 //FIXME: rewrite search algo
1056 for (i
= 0; i
< priv
->freq_table_len
; i
++) {
1057 if (nChannel
== -1 || labs(lFreq
- priv
->freq_table
[i
]) < lFreqDiff
) {
1058 nChannel
= priv
->first_channel
+ i
;
1059 lFreqDiff
= labs(lFreq
- priv
->freq_table
[i
]);
1062 if (nChannel
== -1) {
1063 mp_msg(MSGT_TV
,MSGL_ERR
, MSGTR_TVI_DS_UnableFindNearestChannel
);
1066 hr
= OLE_CALL_ARGS(priv
->pTVTuner
, put_Channel
, nChannel
,
1067 AMTUNER_SUBCHAN_DEFAULT
, AMTUNER_SUBCHAN_DEFAULT
);
1069 mp_msg(MSGT_TV
,MSGL_ERR
,MSGTR_TVI_DS_UnableToSetChannel
, (unsigned int)hr
);
1076 * \brief setting frequency. decides whether use direct call/workaround
1078 * \param priv driver's private data
1079 * \param lFreq frequency in Hz
1081 * \return TVI_CONTROL_TRUE if success
1082 * \return TVI_CONTROL_FALSE if error occured
1084 * \todo check for freq boundary
1086 static int set_frequency(priv_t
* priv
, long lFreq
)
1090 mp_msg(MSGT_TV
, MSGL_DBG4
, "tvi_dshow: set_frequency called\n");
1091 if (!priv
->pTVTuner
)
1092 return TVI_CONTROL_FALSE
;
1093 if (priv
->direct_setfreq_call
) { //using direct call to set frequency
1094 hr
= set_frequency_direct(priv
->pTVTuner
, lFreq
);
1096 mp_msg(MSGT_TV
, MSGL_V
, MSGTR_TVI_DS_DirectSetFreqFailed
);
1097 priv
->direct_setfreq_call
= 0;
1100 if (!priv
->direct_setfreq_call
) {
1101 hr
= set_nearest_freq(priv
, lFreq
);
1104 return TVI_CONTROL_FALSE
;
1106 priv
->pGrabber
->ClearBuffer(priv
->pGrabber
);
1108 return TVI_CONTROL_TRUE
;
1112 * \brief return current frequency from tuner (in Hz)
1114 * \param pTVTuner IAMTVTuner interface of tuner
1115 * \param plFreq address of variable that receives current frequency
1117 * \return S_OK success
1118 * \return E_POINTER pTVTuner==NULL || plFreq==NULL
1119 * \return apropriate error code otherwise
1121 static HRESULT
get_frequency_direct(IAMTVTuner
* pTVTuner
, long *plFreq
)
1124 KSPROPERTY_TUNER_STATUS_S TunerStatus
;
1126 IKsPropertySet
*pKSProp
;
1127 mp_msg(MSGT_TV
, MSGL_DBG4
, "tvi_dshow: get_frequency_direct called\n");
1132 hr
= OLE_QUERYINTERFACE(pTVTuner
, IID_IKsPropertySet
, pKSProp
);
1134 mp_msg(MSGT_TV
, MSGL_DBG2
, "tvi_dshow: Get freq QueryInterface failed\n");
1138 hr
= OLE_CALL_ARGS(pKSProp
, Get
, &PROPSETID_TUNER
,
1139 KSPROPERTY_TUNER_STATUS
,
1140 INSTANCEDATA_OF_PROPERTY_PTR(&TunerStatus
),
1141 INSTANCEDATA_OF_PROPERTY_SIZE(TunerStatus
),
1142 &TunerStatus
, sizeof(TunerStatus
), &cbBytes
);
1144 mp_msg(MSGT_TV
, MSGL_DBG2
, "tvi_dshow: Get freq Get failure\n");
1147 *plFreq
= TunerStatus
.CurrentFrequency
;
1152 * \brief gets current frequency
1154 * \param priv driver's private data structure
1155 * \param plFreq - pointer to long int to store frequency to (in Hz)
1157 * \return TVI_CONTROL_TRUE if success, TVI_CONTROL_FALSE otherwise
1159 static int get_frequency(priv_t
* priv
, long *plFreq
)
1163 mp_msg(MSGT_TV
, MSGL_DBG4
, "tvi_dshow: get_frequency called\n");
1165 if (!plFreq
|| !priv
->pTVTuner
)
1166 return TVI_CONTROL_FALSE
;
1168 if (priv
->direct_getfreq_call
) { //using direct call to get frequency
1169 hr
= get_frequency_direct(priv
->pTVTuner
, plFreq
);
1171 mp_msg(MSGT_TV
, MSGL_INFO
, MSGTR_TVI_DS_DirectGetFreqFailed
);
1172 priv
->direct_getfreq_call
= 0;
1175 if (!priv
->direct_getfreq_call
) {
1176 hr
=OLE_CALL_ARGS(priv
->pTVTuner
, get_VideoFrequency
, plFreq
);
1178 return TVI_CONTROL_FALSE
;
1181 return TVI_CONTROL_TRUE
;
1185 * \brief get tuner capabilities
1187 * \param priv driver's private data
1189 static void get_capabilities(priv_t
* priv
)
1191 long lAvailableFormats
;
1194 long lInputPins
, lOutputPins
, lRelated
, lPhysicalType
;
1198 PIN_DIRECTION ThisPinDir
;
1200 IAMAudioInputMixer
*pIAMixer
;
1202 mp_msg(MSGT_TV
, MSGL_DBG4
, "tvi_dshow: get_capabilities called\n");
1203 if (priv
->pTVTuner
) {
1205 mp_msg(MSGT_TV
, MSGL_V
, MSGTR_TVI_DS_SupportedNorms
);
1206 hr
= OLE_CALL_ARGS(priv
->pTVTuner
, get_AvailableTVFormats
,
1207 &lAvailableFormats
);
1209 tv_available_norms_count
= 0;
1211 for (i
= 0; i
< TV_NORMS_COUNT
; i
++) {
1212 if (lAvailableFormats
& tv_norms
[i
].index
) {
1213 tv_available_norms
[tv_available_norms_count
] = i
;
1214 mp_msg(MSGT_TV
, MSGL_V
, " %d=%s;",
1215 tv_available_norms_count
+ 1, tv_norms
[i
].name
);
1216 tv_available_norms_count
++;
1220 mp_msg(MSGT_TV
, MSGL_INFO
, "\n");
1222 if (priv
->pCrossbar
) {
1223 OLE_CALL_ARGS(priv
->pCrossbar
, get_PinCounts
, &lOutputPins
,
1226 tv_available_inputs
= (long *) malloc(sizeof(long) * lInputPins
);
1227 tv_available_inputs_count
= 0;
1229 mp_msg(MSGT_TV
, MSGL_V
, MSGTR_TVI_DS_AvailableVideoInputs
);
1230 for (i
= 0; i
< lInputPins
; i
++) {
1231 OLE_CALL_ARGS(priv
->pCrossbar
, get_CrossbarPinInfo
, 1, i
,
1232 &lRelated
, &lPhysicalType
);
1234 if (lPhysicalType
< 0x1000) {
1235 tv_available_inputs
[tv_available_inputs_count
++] = i
;
1236 mp_msg(MSGT_TV
, MSGL_V
, " %d=%s;",
1237 tv_available_inputs_count
- 1,
1238 physcon2str(lPhysicalType
));
1241 mp_msg(MSGT_TV
, MSGL_INFO
, "\n");
1243 set_crossbar_input(priv
, 0);
1246 if (priv
->adev_index
!= -1) {
1247 hr
= OLE_CALL_ARGS(priv
->chains
[1]->pCaptureFilter
, EnumPins
, &pEnum
);
1250 mp_msg(MSGT_TV
, MSGL_V
, MSGTR_TVI_DS_AvailableAudioInputs
);
1252 while (OLE_CALL_ARGS(pEnum
, Next
, 1, &pPin
, NULL
) == S_OK
) {
1253 memset(&pi
, 0, sizeof(pi
));
1254 memset(tmp
, 0, 200);
1255 OLE_CALL_ARGS(pPin
, QueryDirection
, &ThisPinDir
);
1256 if (ThisPinDir
== PINDIR_INPUT
) {
1257 OLE_CALL_ARGS(pPin
, QueryPinInfo
, &pi
);
1258 wtoa(pi
.achName
, tmp
, 200);
1259 OLE_RELEASE_SAFE(pi
.pFilter
);
1260 mp_msg(MSGT_TV
, MSGL_V
, " %d=%s", i
, tmp
);
1261 mp_msg(MSGT_TV
, MSGL_DBG3
, " (%p)", pPin
);
1262 hr
= OLE_QUERYINTERFACE(pPin
, IID_IAMAudioInputMixer
,pIAMixer
);
1263 if (SUCCEEDED(hr
)) {
1264 if (i
== priv
->tv_param
->audio_id
) {
1265 OLE_CALL_ARGS(pIAMixer
, put_Enable
, TRUE
);
1266 if(priv
->tv_param
->volume
>0)
1267 OLE_CALL_ARGS(pIAMixer
, put_MixLevel
, 0.01 * priv
->tv_param
->volume
);
1270 OLE_CALL_ARGS(pIAMixer
, put_MixLevel
, 1.0);
1272 mp_msg(MSGT_TV
, MSGL_V
, MSGTR_TVI_DS_InputSelected
);
1274 OLE_CALL_ARGS(pIAMixer
, put_Enable
, FALSE
);
1276 OLE_CALL_ARGS(pIAMixer
, put_MixLevel
, 0.0);
1279 OLE_RELEASE_SAFE(pIAMixer
);
1281 mp_msg(MSGT_TV
, MSGL_V
, ";");
1282 OLE_RELEASE_SAFE(pPin
);
1286 mp_msg(MSGT_TV
, MSGL_INFO
, "\n");
1287 OLE_RELEASE_SAFE(pEnum
);
1292 *---------------------------------------------------------------------------------------
1294 * Filter related methods
1296 *---------------------------------------------------------------------------------------
1299 * \brief routine for reconnecting two pins with new media type
1300 * \param pGraph IGraphBuilder interface
1301 * \param chan chain data
1302 * \param pmt [in/out] new mediatype for pin connection
1304 * \return S_OK if operation successfult, error code otherwise
1305 * will also return media type of new connection into pmt variable
1307 static HRESULT
reconnect_pins(IGraphBuilder
*pGraph
, chain_t
*chain
, AM_MEDIA_TYPE
*pmt
)
1309 AM_MEDIA_TYPE old_mt
;
1313 /* save old media type for reconnection in case of error */
1314 hr
= OLE_CALL_ARGS(chain
->pCapturePin
, ConnectionMediaType
, &old_mt
);
1318 hr
= OLE_CALL(chain
->pCapturePin
, Disconnect
);
1322 hr
= OLE_CALL_ARGS(chain
->pSG
, SetMediaType
, pmt
);
1326 hr
= OLE_CALL_ARGS(pGraph
, Connect
, chain
->pCapturePin
, chain
->pSGIn
);
1329 OLE_CALL_ARGS(chain
->pSG
, SetMediaType
, &old_mt
);
1330 OLE_CALL_ARGS(pGraph
, Connect
, chain
->pCapturePin
, chain
->pSGIn
);
1333 hr
= OLE_CALL_ARGS(chain
->pCapturePin
, ConnectionMediaType
, &old_mt
);
1339 CopyMediaType(pmt
, &old_mt
);
1340 FreeMediaType(&old_mt
);
1345 * \brief building in graph audio/video capture chain
1347 * \param priv driver's private data
1348 * \param pCaptureFilter pointer to capture device's IBaseFilter interface
1349 * \param pbuf ringbuffer data structure
1350 * \param pmt media type for chain (AM_MEDIA_TYPE)
1352 * \note routine does not frees memory, allocated for grabber_rinbuffer_s structure
1354 static HRESULT
build_sub_graph(priv_t
* priv
, chain_t
* chain
, const GUID
* ppin_category
)
1357 int nFormatProbed
= 0;
1362 IBaseFilter
*pNR
= NULL
;
1366 //No supported formats
1367 if(!chain
->arpmt
[0])
1371 hr
= OLE_CALL_ARGS(priv
->pBuilder
, FindPin
,
1372 (IUnknown
*) chain
->pCaptureFilter
,
1373 PINDIR_OUTPUT
, ppin_category
,
1374 chain
->majortype
, FALSE
, 0, &chain
->pCapturePin
);
1376 mp_msg(MSGT_TV
,MSGL_DBG2
, "tvi_dshow: FindPin(pCapturePin) call failed. Error:0x%x\n", (unsigned int)hr
);
1379 /* Addinf SampleGrabber filter for video stream */
1380 hr
= CoCreateInstance((GUID
*) & CLSID_SampleGrabber
, NULL
,CLSCTX_INPROC_SERVER
, &IID_IBaseFilter
,(void *) &chain
->pSGF
);
1382 mp_msg(MSGT_TV
,MSGL_DBG2
, "tvi_dshow: CoCreateInstance(SampleGrabber) call failed. Error:0x%x\n", (unsigned int)hr
);
1385 hr
= OLE_CALL_ARGS(priv
->pGraph
, AddFilter
, chain
->pSGF
, L
"Sample Grabber");
1387 mp_msg(MSGT_TV
,MSGL_DBG2
,"tvi_dshow: AddFilter(SampleGrabber) call failed. Error:0x%x\n", (unsigned int)hr
);
1390 hr
= OLE_CALL_ARGS(priv
->pBuilder
, FindPin
, (IUnknown
*) chain
->pSGF
,PINDIR_INPUT
, NULL
, NULL
, FALSE
, 0, &chain
->pSGIn
);
1392 mp_msg(MSGT_TV
,MSGL_DBG2
,"tvi_dshow: FindPin(pSGIn) call failed. Error:0x%x\n", (unsigned int)hr
);
1395 hr
= OLE_CALL_ARGS(priv
->pBuilder
, FindPin
, (IUnknown
*) chain
->pSGF
,PINDIR_OUTPUT
, NULL
, NULL
, FALSE
, 0, &pSGOut
);
1397 mp_msg(MSGT_TV
,MSGL_DBG2
,"tvi_dshow: FindPin(pSGOut) call failed. Error:0x%x\n", (unsigned int)hr
);
1401 /* creating ringbuffer for video samples */
1402 chain
->pCSGCB
= CSampleGrabberCB_Create(chain
->rbuf
);
1404 mp_msg(MSGT_TV
,MSGL_DBG2
, "tvi_dshow: CSampleGrabberCB_Create(pbuf) call failed. Error:0x%x\n", (unsigned int)E_OUTOFMEMORY
);
1408 /* initializing SampleGrabber filter */
1409 hr
= OLE_QUERYINTERFACE(chain
->pSGF
, IID_ISampleGrabber
, chain
->pSG
);
1411 mp_msg(MSGT_TV
,MSGL_DBG2
,"tvi_dshow: QueryInterface(IID_ISampleGrabber) call failed. Error:0x%x\n", (unsigned int)hr
);
1414 // hr = OLE_CALL_ARGS(pSG, SetCallback, (ISampleGrabberCB *) pCSGCB, 1); //we want to receive copy of sample's data
1415 hr
= OLE_CALL_ARGS(chain
->pSG
, SetCallback
, (ISampleGrabberCB
*) chain
->pCSGCB
, 0); //we want to receive sample
1418 mp_msg(MSGT_TV
,MSGL_DBG2
,"tvi_dshow: SetCallback(pSG) call failed. Error:0x%x\n", (unsigned int)hr
);
1421 hr
= OLE_CALL_ARGS(chain
->pSG
, SetOneShot
, FALSE
); //... for all frames
1423 mp_msg(MSGT_TV
,MSGL_DBG2
,"tvi_dshow: SetOneShot(pSG) call failed. Error:0x%x\n", (unsigned int)hr
);
1426 hr
= OLE_CALL_ARGS(chain
->pSG
, SetBufferSamples
, FALSE
); //... do not buffer samples in sample grabber
1428 mp_msg(MSGT_TV
,MSGL_DBG2
,"tvi_dshow: SetBufferSamples(pSG) call failed. Error:0x%x\n", (unsigned int)hr
);
1432 if(priv
->tv_param
->normalize_audio_chunks
&& chain
->type
==audio
){
1433 set_buffer_preference(20,(WAVEFORMATEX
*)(chain
->arpmt
[nFormatProbed
]->pbFormat
),chain
->pCapturePin
,chain
->pSGIn
);
1436 for(nFormatProbed
=0; chain
->arpmt
[nFormatProbed
]; nFormatProbed
++)
1438 DisplayMediaType("Probing format", chain
->arpmt
[nFormatProbed
]);
1439 hr
= OLE_CALL_ARGS(chain
->pSG
, SetMediaType
, chain
->arpmt
[nFormatProbed
]); //set desired mediatype
1441 mp_msg(MSGT_TV
,MSGL_DBG2
,"tvi_dshow: SetMediaType(pSG) call failed. Error:0x%x\n", (unsigned int)hr
);
1444 /* connecting filters together: VideoCapture --> SampleGrabber */
1445 hr
= OLE_CALL_ARGS(priv
->pGraph
, Connect
, chain
->pCapturePin
, chain
->pSGIn
);
1447 mp_msg(MSGT_TV
,MSGL_DBG2
,"tvi_dshow: Unable to create pCapturePin<->pSGIn connection. Error:0x%x\n", (unsigned int)hr
);
1453 if(!chain
->arpmt
[nFormatProbed
])
1455 mp_msg(MSGT_TV
, MSGL_WARN
, "tvi_dshow: Unable to negotiate media format\n");
1460 hr
= OLE_CALL_ARGS(chain
->pCapturePin
, ConnectionMediaType
, chain
->pmt
);
1463 mp_msg(MSGT_TV
, MSGL_WARN
, MSGTR_TVI_DS_GetActualMediatypeFailed
, (unsigned int)hr
);
1466 if(priv
->tv_param
->hidden_video_renderer
){
1467 IEnumFilters
* pEnum
;
1468 IBaseFilter
* pFilter
;
1470 hr
=OLE_CALL_ARGS(priv
->pBuilder
,RenderStream
,NULL
,NULL
,(IUnknown
*)chain
->pCapturePin
,NULL
,NULL
);
1472 OLE_CALL_ARGS(priv
->pGraph
, EnumFilters
, &pEnum
);
1473 while (OLE_CALL_ARGS(pEnum
, Next
, 1, &pFilter
, NULL
) == S_OK
) {
1474 LPVIDEOWINDOW pVideoWindow
;
1475 hr
= OLE_QUERYINTERFACE(pFilter
, IID_IVideoWindow
, pVideoWindow
);
1478 OLE_CALL_ARGS(pVideoWindow
,put_Visible
,/* OAFALSE*/ 0);
1479 OLE_CALL_ARGS(pVideoWindow
,put_AutoShow
,/* OAFALSE*/ 0);
1480 OLE_RELEASE_SAFE(pVideoWindow
);
1482 OLE_RELEASE_SAFE(pFilter
);
1484 OLE_RELEASE_SAFE(pEnum
);
1489 Code below is disabled, because terminating chain with NullRenderer leads to jerky video.
1490 Perhaps, this happens because NullRenderer filter discards each received
1491 frame while discarded frames causes live source filter to dramatically reduce frame rate.
1493 /* adding sink for video stream */
1494 hr
= CoCreateInstance((GUID
*) & CLSID_NullRenderer
, NULL
,CLSCTX_INPROC_SERVER
, &IID_IBaseFilter
,(void *) &pNR
);
1496 mp_msg(MSGT_TV
,MSGL_DBG2
,"tvi_dshow: CoCreateInstance(NullRenderer) call failed. Error:0x%x\n", (unsigned int)hr
);
1499 hr
= OLE_CALL_ARGS(priv
->pGraph
, AddFilter
, pNR
, L
"Null Renderer");
1501 mp_msg(MSGT_TV
,MSGL_DBG2
,"tvi_dshow: AddFilter(NullRenderer) call failed. Error:0x%x\n", (unsigned int)hr
);
1504 hr
= OLE_CALL_ARGS(priv
->pBuilder
, FindPin
, (IUnknown
*) pNR
,PINDIR_INPUT
, NULL
, NULL
, FALSE
, 0, &pNRIn
);
1506 mp_msg(MSGT_TV
,MSGL_DBG2
,"tvi_dshow: FindPin(pNRIn) call failed. Error:0x%x\n", (unsigned int)hr
);
1510 Prevent ending VBI chain with NullRenderer filter, because this causes VBI pin disconnection
1512 if(memcmp(&(arpmt
[nFormatProbed
]->majortype
),&MEDIATYPE_VBI
,16)){
1513 /* connecting filters together: SampleGrabber --> NullRenderer */
1514 hr
= OLE_CALL_ARGS(priv
->pGraph
, Connect
, pSGOut
, pNRIn
);
1516 mp_msg(MSGT_TV
,MSGL_DBG2
,"tvi_dshow: Unable to create pSGOut<->pNRIn connection. Error:0x%x\n", (unsigned int)hr
);
1526 OLE_RELEASE_SAFE(pSGOut
);
1527 OLE_RELEASE_SAFE(pNR
);
1528 OLE_RELEASE_SAFE(pNRIn
);
1534 * \brief configures crossbar for grabbing video stream from given input
1536 * \param priv driver's private data
1537 * \param input index of available video input to get data from
1539 * \return TVI_CONTROL_TRUE success
1540 * \return TVI_CONTROL_FALSE error
1542 static int set_crossbar_input(priv_t
* priv
, int input
)
1545 int i
, nVideoDecoder
, nAudioDecoder
;
1546 long lInput
, lInputRelated
, lRelated
, lPhysicalType
, lOutputPins
,
1549 mp_msg(MSGT_TV
, MSGL_DBG4
, "tvi_dshow: Configuring crossbar\n");
1550 if (!priv
->pCrossbar
|| input
< 0
1551 || input
>= tv_available_inputs_count
)
1552 return TVI_CONTROL_FALSE
;
1554 OLE_CALL_ARGS(priv
->pCrossbar
, get_PinCounts
, &lOutputPins
, &lInputPins
);
1556 lInput
= tv_available_inputs
[input
];
1558 if (lInput
< 0 || lInput
>= lInputPins
)
1559 return TVI_CONTROL_FALSE
;
1561 OLE_CALL_ARGS(priv
->pCrossbar
, get_CrossbarPinInfo
, 1 /* input */ , lInput
,
1562 &lInputRelated
, &lPhysicalType
);
1564 nVideoDecoder
= nAudioDecoder
= -1;
1565 for (i
= 0; i
< lOutputPins
; i
++) {
1566 OLE_CALL_ARGS(priv
->pCrossbar
, get_CrossbarPinInfo
, 0 /*output */ , i
,
1567 &lRelated
, &lPhysicalType
);
1568 if (lPhysicalType
== PhysConn_Video_VideoDecoder
)
1570 if (lPhysicalType
== PhysConn_Audio_AudioDecoder
)
1573 if (nVideoDecoder
>= 0) {
1574 //connecting given input with video decoder
1575 hr
= OLE_CALL_ARGS(priv
->pCrossbar
, Route
, nVideoDecoder
, lInput
);
1577 mp_msg(MSGT_TV
,MSGL_ERR
,MSGTR_TVI_DS_UnableConnectInputVideoDecoder
, (unsigned int)hr
);
1578 return TVI_CONTROL_FALSE
;
1581 if (nAudioDecoder
>= 0 && lInputRelated
>= 0) {
1582 hr
= OLE_CALL_ARGS(priv
->pCrossbar
, Route
, nAudioDecoder
,
1585 mp_msg(MSGT_TV
,MSGL_ERR
,MSGTR_TVI_DS_UnableConnectInputAudioDecoder
, (unsigned int)hr
);
1586 return TVI_CONTROL_FALSE
;
1589 return TVI_CONTROL_TRUE
;
1593 * \brief adjusts video control (hue,saturation,contrast,brightess)
1595 * \param priv driver's private data
1596 * \param control which control to adjust
1597 * \param value new value for control (0-100)
1599 * \return TVI_CONTROL_TRUE success
1600 * \return TVI_CONTROL_FALSE error
1602 static int set_control(priv_t
* priv
, int control
, int value
)
1604 long lMin
, lMax
, lStepping
, lDefault
, lFlags
, lValue
;
1607 mp_msg(MSGT_TV
, MSGL_DBG4
, "tvi_dshow: set_control called\n");
1608 if (value
< -100 || value
> 100 || !priv
->pVideoProcAmp
)
1609 return TVI_CONTROL_FALSE
;
1611 hr
= OLE_CALL_ARGS(priv
->pVideoProcAmp
, GetRange
, control
,
1612 &lMin
, &lMax
, &lStepping
, &lDefault
, &lFlags
);
1613 if (FAILED(hr
) || lFlags
!= VideoProcAmp_Flags_Manual
)
1614 return TVI_CONTROL_FALSE
;
1616 lValue
= lMin
+ (value
+ 100) * (lMax
- lMin
) / 200;
1618 Workaround for ATI AIW 7500. The driver reports: max=255, stepping=256
1620 if (lStepping
> lMax
) {
1621 mp_msg(MSGT_TV
, MSGL_DBG3
,
1622 "tvi_dshow: Stepping (%ld) is bigger than max value (%ld) for control %d. Assuming 1\n",
1623 lStepping
, lMax
,control
);
1626 lValue
-= lValue
% lStepping
;
1627 hr
= OLE_CALL_ARGS(priv
->pVideoProcAmp
, Set
, control
, lValue
,
1628 VideoProcAmp_Flags_Manual
);
1630 return TVI_CONTROL_FALSE
;
1632 return TVI_CONTROL_TRUE
;
1636 * \brief get current value of video control (hue,saturation,contrast,brightess)
1638 * \param priv driver's private data
1639 * \param control which control to adjust
1640 * \param pvalue address of variable thar receives current value
1642 * \return TVI_CONTROL_TRUE success
1643 * \return TVI_CONTROL_FALSE error
1645 static int get_control(priv_t
* priv
, int control
, int *pvalue
)
1647 long lMin
, lMax
, lStepping
, lDefault
, lFlags
, lValue
;
1650 mp_msg(MSGT_TV
, MSGL_DBG4
, "tvi_dshow: get_control called\n");
1651 if (!pvalue
|| !priv
->pVideoProcAmp
)
1652 return TVI_CONTROL_FALSE
;
1654 hr
= OLE_CALL_ARGS(priv
->pVideoProcAmp
, GetRange
, control
,
1655 &lMin
, &lMax
, &lStepping
, &lDefault
, &lFlags
);
1657 return TVI_CONTROL_FALSE
;
1660 return TVI_CONTROL_TRUE
;
1663 hr
= OLE_CALL_ARGS(priv
->pVideoProcAmp
, Get
, control
, &lValue
, &lFlags
);
1665 return TVI_CONTROL_FALSE
;
1667 *pvalue
= 200 * (lValue
- lMin
) / (lMax
- lMin
) - 100;
1669 return TVI_CONTROL_TRUE
;
1673 * \brief create AM_MEDIA_TYPE structure, corresponding to given FourCC code and width/height/fps
1674 * \param fcc FourCC code for video format
1675 * \param width picture width
1676 * \param height pciture height
1677 * \param fps frames per second (required for bitrate calculation)
1679 * \return pointer to AM_MEDIA_TYPE structure if success, NULL - otherwise
1681 static AM_MEDIA_TYPE
* create_video_format(int fcc
, int width
, int height
, int fps
)
1685 VIDEOINFOHEADER vHdr
;
1687 /* Check given fcc in lookup table*/
1688 for(i
=0; img_fmt_list
[i
].fmt
&& img_fmt_list
[i
].fmt
!=fcc
; i
++) /* NOTHING */;
1689 if(!img_fmt_list
[i
].fmt
)
1692 memset(&mt
, 0, sizeof(AM_MEDIA_TYPE
));
1693 memset(&vHdr
, 0, sizeof(VIDEOINFOHEADER
));
1695 vHdr
.bmiHeader
.biSize
= sizeof(vHdr
.bmiHeader
);
1696 vHdr
.bmiHeader
.biWidth
= width
;
1697 vHdr
.bmiHeader
.biHeight
= height
;
1698 //FIXME: is biPlanes required too?
1699 //vHdr.bmiHeader.biPlanes = img_fmt_list[i].nPlanes;
1700 vHdr
.bmiHeader
.biBitCount
= img_fmt_list
[i
].nBits
;
1701 vHdr
.bmiHeader
.biCompression
= img_fmt_list
[i
].nCompression
;
1702 vHdr
.bmiHeader
.biSizeImage
= width
* height
* img_fmt_list
[i
].nBits
/ 8;
1703 vHdr
.dwBitRate
= vHdr
.bmiHeader
.biSizeImage
* 8 * fps
;
1705 mt
.pbFormat
= (char*)&vHdr
;
1706 mt
.cbFormat
= sizeof(vHdr
);
1708 mt
.majortype
= MEDIATYPE_Video
;
1709 mt
.subtype
= *img_fmt_list
[i
].subtype
;
1710 mt
.formattype
= FORMAT_VideoInfo
;
1712 mt
.bFixedSizeSamples
= 1;
1713 mt
.bTemporalCompression
= 0;
1714 mt
.lSampleSize
= vHdr
.bmiHeader
.biSizeImage
;
1716 return CreateMediaType(&mt
);
1720 * \brief extracts fcc,width,height from AM_MEDIA_TYPE
1722 * \param pmt pointer to AM_MEDIA_TYPE to extract data from
1723 * \param pfcc address of variable that receives FourCC
1724 * \param pwidth address of variable that receives width
1725 * \param pheight address of variable that recevies height
1727 * \return 1 if data extracted successfully, 0 - otherwise
1729 static int extract_video_format(AM_MEDIA_TYPE
* pmt
, int *pfcc
,
1730 int *pwidth
, int *pheight
)
1732 mp_msg(MSGT_TV
, MSGL_DBG4
, "tvi_dshow: extract_video_format called\n");
1737 if (memcmp(&(pmt
->formattype
), &FORMAT_VideoInfo
, 16) != 0)
1740 *pfcc
= subtype2imgfmt(&(pmt
->subtype
));
1742 *pwidth
= ((VIDEOINFOHEADER
*) pmt
->pbFormat
)->bmiHeader
.biWidth
;
1744 *pheight
= ((VIDEOINFOHEADER
*) pmt
->pbFormat
)->bmiHeader
.biHeight
;
1749 * \brief extracts samplerate,bits,channels from AM_MEDIA_TYPE
1751 * \param pmt pointer to AM_MEDIA_TYPE to extract data from
1752 * \param pfcc address of variable that receives samplerate
1753 * \param pwidth address of variable that receives number of bits per sample
1754 * \param pheight address of variable that recevies number of channels
1756 * \return 1 if data extracted successfully, 0 - otherwise
1758 static int extract_audio_format(AM_MEDIA_TYPE
* pmt
, int *psamplerate
,
1759 int *pbits
, int *pchannels
)
1761 mp_msg(MSGT_TV
, MSGL_DBG4
, "tvi_dshow: extract_audio_format called\n");
1766 if (memcmp(&(pmt
->formattype
), &FORMAT_WaveFormatEx
, 16) != 0)
1769 *psamplerate
= ((WAVEFORMATEX
*) pmt
->pbFormat
)->nSamplesPerSec
;
1771 *pbits
= ((WAVEFORMATEX
*) pmt
->pbFormat
)->wBitsPerSample
;
1773 *pchannels
= ((WAVEFORMATEX
*) pmt
->pbFormat
)->nChannels
;
1778 * \brief checks if AM_MEDIA_TYPE compatible with given samplerate,bits,channels
1780 * \param pmt pointer to AM_MEDIA_TYPE for check
1781 * \param samplerate audio samplerate
1782 * \param bits bits per sample
1783 * \param channels number of audio channels
1785 * \return 1 if AM_MEDIA_TYPE compatible
1788 static int check_audio_format(AM_MEDIA_TYPE
* pmt
, int samplerate
,
1789 int bits
, int channels
)
1791 mp_msg(MSGT_TV
, MSGL_DBG4
, "tvi_dshow: check_audio_format called\n");
1794 if (memcmp(&(pmt
->majortype
), &MEDIATYPE_Audio
, 16) != 0)
1796 if (memcmp(&(pmt
->subtype
), &MEDIASUBTYPE_PCM
, 16) != 0)
1798 if (memcmp(&(pmt
->formattype
), &FORMAT_WaveFormatEx
, 16) != 0)
1802 if (((WAVEFORMATEX
*) pmt
->pbFormat
)->nSamplesPerSec
!= samplerate
)
1804 if (((WAVEFORMATEX
*) pmt
->pbFormat
)->wBitsPerSample
!= bits
)
1807 && ((WAVEFORMATEX
*) pmt
->pbFormat
)->nChannels
!= channels
)
1814 * \brief checks if AM_MEDIA_TYPE compatible with given fcc,width,height
1816 * \param pmt pointer to AM_MEDIA_TYPE for check
1817 * \param fcc FourCC (compression)
1818 * \param width width of picture
1819 * \param height height of picture
1821 * \return 1 if AM_MEDIA_TYPE compatible
1825 * width and height are currently not used
1828 * add width/height check
1830 static int check_video_format(AM_MEDIA_TYPE
* pmt
, int fcc
, int width
,
1833 mp_msg(MSGT_TV
, MSGL_DBG4
, "tvi_dshow: check_video_format called\n");
1836 if (memcmp(&(pmt
->majortype
), &MEDIATYPE_Video
, 16) != 0)
1838 if (subtype2imgfmt(&(pmt
->subtype
)) != fcc
)
1844 * \brief converts DirectShow subtype to MPlayer's IMGFMT
1846 * \param subtype DirectShow subtype for video format
1848 * \return MPlayer's IMGFMT or 0 if error occured
1850 static int subtype2imgfmt(const GUID
* subtype
)
1853 for (i
= 0; img_fmt_list
[i
].fmt
; i
++) {
1854 if (memcmp(subtype
, img_fmt_list
[i
].subtype
, 16) == 0)
1855 return img_fmt_list
[i
].fmt
;
1861 * \brief prints filter name and it pins
1863 * \param pFilter - IBaseFilter to get data from
1865 * \return S_OK if success, error code otherwise
1867 static HRESULT
show_filter_info(IBaseFilter
* pFilter
)
1871 LPENUMPINS pEnum
= 0;
1873 PIN_DIRECTION ThisPinDir
;
1878 mp_msg(MSGT_TV
, MSGL_DBG4
, "tvi_dshow: show_filter_info called\n");
1879 memset(&fi
, 0, sizeof(fi
));
1880 memset(tmp
, 0, 200);
1882 OLE_CALL_ARGS(pFilter
, QueryFilterInfo
, &fi
);
1883 OLE_RELEASE_SAFE(fi
.pGraph
);
1884 wtoa(fi
.achName
, tmp
, 200);
1885 mp_msg(MSGT_TV
, MSGL_DBG2
, "tvi_dshow: BaseFilter (%p): Name=%s, Graph=%p output pins:",
1886 pFilter
, tmp
, fi
.pGraph
);
1887 hr
= OLE_CALL_ARGS(pFilter
, EnumPins
, &pEnum
);
1891 while (OLE_CALL_ARGS(pEnum
, Next
, 1, &pPin
, NULL
) == S_OK
) {
1892 memset(&pi
, 0, sizeof(pi
));
1893 memset(tmp
, 0, 200);
1894 OLE_CALL_ARGS(pPin
, QueryDirection
, &ThisPinDir
);
1895 if (ThisPinDir
== PINDIR_OUTPUT
) {
1896 OLE_CALL_ARGS(pPin
, QueryPinInfo
, &pi
);
1897 wtoa(pi
.achName
, tmp
, 200);
1898 OLE_RELEASE_SAFE(pi
.pFilter
);
1899 mp_msg(MSGT_TV
, MSGL_DBG2
, " %d=%s", i
, tmp
);
1900 mp_msg(MSGT_TV
, MSGL_DBG3
, " (%p)", pPin
);
1901 mp_msg(MSGT_TV
, MSGL_DBG2
, ";");
1902 OLE_RELEASE_SAFE(pPin
);
1906 mp_msg(MSGT_TV
, MSGL_DBG2
, "\n");
1907 OLE_RELEASE_SAFE(pEnum
);
1912 * \brief gets device's frendly in ANSI encoding
1914 * \param pM IMoniker interface, got in enumeration process
1915 * \param category device category
1917 * \return TVI_CONTROL_TRUE if operation succeded, TVI_CONTROL_FALSE - otherwise
1919 static int get_device_name(IMoniker
* pM
, char *pBuf
, int nLen
)
1923 IPropertyBag
*pPropBag
;
1924 hr
= OLE_CALL_ARGS(pM
, BindToStorage
, 0, 0, &IID_IPropertyBag
,(void *) &pPropBag
);
1926 mp_msg(MSGT_TV
, MSGL_DBG2
, "tvi_dshow: Call to BindToStorage failed\n");
1927 return TVI_CONTROL_FALSE
;
1930 hr
= OLE_CALL_ARGS(pPropBag
, Read
, L
"Description", (LPVARIANT
) & var
,
1933 hr
= OLE_CALL_ARGS(pPropBag
, Read
, L
"FriendlyName", (LPVARIANT
) & var
,
1936 OLE_RELEASE_SAFE(pPropBag
);
1937 if (SUCCEEDED(hr
)) {
1938 wtoa(var
.bstrVal
, pBuf
, nLen
);
1939 return TVI_CONTROL_TRUE
;
1941 return TVI_CONTROL_FALSE
;
1945 * \brief find capture device at given index
1947 * \param index device index to search for (-1 mean only print available)
1948 * \param category device category
1950 * \return IBaseFilter interface for capture device with given index
1952 * Sample values for category:
1953 * CLSID_VideoInputDeviceCategory - Video Capture Sources
1954 * CLSID_AudioInputDeviceCategory - Audio Capture Sources
1955 * See DirectShow SDK documentation for other possible values
1957 static IBaseFilter
*find_capture_device(int index
, REFCLSID category
)
1959 IBaseFilter
*pFilter
= NULL
;
1960 ICreateDevEnum
*pDevEnum
= NULL
;
1961 IEnumMoniker
*pClassEnum
= NULL
;
1966 char tmp
[DEVICE_NAME_MAX_LEN
+ 1];
1967 hr
= CoCreateInstance((GUID
*) & CLSID_SystemDeviceEnum
, NULL
,
1968 CLSCTX_INPROC_SERVER
, &IID_ICreateDevEnum
,
1969 (void *) &pDevEnum
);
1971 mp_msg(MSGT_TV
, MSGL_DBG2
, "tvi_dshow: Unable to create device enumerator\n");
1975 hr
= OLE_CALL_ARGS(pDevEnum
, CreateClassEnumerator
, category
, &pClassEnum
, 0);
1976 OLE_RELEASE_SAFE(pDevEnum
);
1978 mp_msg(MSGT_TV
, MSGL_DBG2
, "tvi_dshow: Unable to create class enumerator\n");
1981 if (hr
== S_FALSE
) {
1982 mp_msg(MSGT_TV
, MSGL_DBG2
, "tvi_dshow: No capture devices found\n");
1986 OLE_CALL(pClassEnum
,Reset
);
1987 for (i
= 0; OLE_CALL_ARGS(pClassEnum
, Next
, 1, &pM
, &cFetched
) == S_OK
; i
++) {
1988 if(get_device_name(pM
, tmp
, DEVICE_NAME_MAX_LEN
)!=TVI_CONTROL_TRUE
)
1989 mp_msg(MSGT_TV
, MSGL_ERR
, MSGTR_TVI_DS_UnableGetDeviceName
, i
);
1991 mp_msg(MSGT_TV
, MSGL_V
, MSGTR_TVI_DS_DeviceName
, i
, tmp
);
1992 if (index
!= -1 && i
== index
) {
1993 mp_msg(MSGT_TV
, MSGL_INFO
, MSGTR_TVI_DS_UsingDevice
, index
, tmp
);
1994 hr
= OLE_CALL_ARGS(pM
, BindToObject
, 0, 0, &IID_IBaseFilter
,(void *) &pFilter
);
1998 OLE_RELEASE_SAFE(pM
);
2000 if (index
!= -1 && !pFilter
) {
2001 mp_msg(MSGT_TV
, MSGL_ERR
, MSGTR_TVI_DS_DeviceNotFound
,
2004 OLE_RELEASE_SAFE(pClassEnum
);
2010 * \brief get array of available formats through call to IAMStreamConfig::GetStreamCaps
2012 * \praram[in] chain chain data structure
2014 * \return S_OK success
2015 * \return E_POINTER one of parameters is NULL
2016 * \return E_FAIL required size of buffer is unknown for given media type
2017 * \return E_OUTOFMEMORY not enough memory
2018 * \return other error code from called methods
2021 * last items of chain->arpmt and chain->arStreamCaps will be NULL
2023 static HRESULT
get_available_formats_stream(chain_t
*chain
)
2025 AM_MEDIA_TYPE
**arpmt
;
2032 mp_msg(MSGT_TV
, MSGL_DBG4
,
2033 "tvi_dshow: get_available_formats_stream called\n");
2035 if (!chain
->pStreamConfig
)
2038 hr
=OLE_CALL_ARGS(chain
->pStreamConfig
, GetNumberOfCapabilities
, &count
, &size
);
2040 mp_msg(MSGT_TV
, MSGL_DBG4
,
2041 "tvi_dshow: Call to GetNumberOfCapabilities failed (get_available_formats_stream)\n");
2044 if (chain
->type
== video
){
2045 if (size
!= sizeof(VIDEO_STREAM_CONFIG_CAPS
)) {
2046 mp_msg(MSGT_TV
, MSGL_DBG4
,
2047 "tvi_dshow: Wrong video structure size for GetNumberOfCapabilities (get_available_formats_stream)\n");
2050 } else if (chain
->type
== audio
){
2051 if (size
!= sizeof(AUDIO_STREAM_CONFIG_CAPS
)) {
2052 mp_msg(MSGT_TV
, MSGL_DBG4
,
2053 "tvi_dshow: Wrong audio structure size for GetNumberOfCapabilities (get_available_formats_stream)\n");
2057 mp_msg(MSGT_TV
, MSGL_ERR
, MSGTR_TVI_DS_UnsupportedMediaType
,"get_available_formats_stream");
2062 arpmt
= (AM_MEDIA_TYPE
**) malloc((count
+ 1) * sizeof(AM_MEDIA_TYPE
*));
2064 memset(arpmt
, 0, (count
+ 1) * sizeof(AM_MEDIA_TYPE
*));
2066 pBuf
= (void **) malloc((count
+ 1) * sizeof(void *));
2068 memset(pBuf
, 0, (count
+ 1) * sizeof(void *));
2070 for (i
= 0; i
< count
; i
++) {
2071 pBuf
[i
] = malloc(size
);
2076 hr
= OLE_CALL_ARGS(chain
->pStreamConfig
, GetStreamCaps
, i
,
2077 &(arpmt
[i
]), pBuf
[i
]);
2082 chain
->arpmt
= arpmt
;
2083 chain
->arStreamCaps
= pBuf
;
2089 for (i
= 0; i
< count
; i
++) {
2090 if (pBuf
&& pBuf
[i
])
2092 if (arpmt
&& arpmt
[i
])
2093 DeleteMediaType(arpmt
[i
]);
2100 mp_msg(MSGT_TV
, MSGL_DBG4
, "tvi_dshow: Call to GetStreamCaps failed (get_available_formats_stream)\n");
2103 return E_OUTOFMEMORY
;
2109 * \brief returns allocates an array and store available media formats for given pin type to it
2111 * \param pBuilder ICaptureGraphBuilder2 interface of graph builder
2112 * \param chain chain data structure
2114 * \return S_OK success
2115 * \return E_POINTER one of given pointers is null
2116 * \return apropriate error code otherwise
2118 static HRESULT
get_available_formats_pin(ICaptureGraphBuilder2
* pBuilder
,
2121 IEnumMediaTypes
*pEnum
;
2127 AM_MEDIA_TYPE
**arpmt
; //This will be real array
2128 VIDEO_STREAM_CONFIG_CAPS
*pVideoCaps
;
2129 AUDIO_STREAM_CONFIG_CAPS
*pAudioCaps
;
2132 mp_msg(MSGT_TV
, MSGL_DBG4
,
2133 "tvi_dshow: get_available_formats_pin called\n");
2134 if (!pBuilder
|| !chain
->pCaptureFilter
)
2137 if (!chain
->pCapturePin
)
2139 hr
= OLE_CALL_ARGS(pBuilder
, FindPin
,
2140 (IUnknown
*) chain
->pCaptureFilter
,
2141 PINDIR_OUTPUT
, &PIN_CATEGORY_CAPTURE
,
2142 chain
->majortype
, FALSE
, 0, &chain
->pCapturePin
);
2144 if (!chain
->pCapturePin
)
2147 if (chain
->type
== video
) {
2148 size
= sizeof(VIDEO_STREAM_CONFIG_CAPS
);
2149 } else if (chain
->type
== audio
) {
2150 size
= sizeof(AUDIO_STREAM_CONFIG_CAPS
);
2152 mp_msg(MSGT_TV
, MSGL_ERR
, MSGTR_TVI_DS_UnsupportedMediaType
,"get_available_formats_pin");
2156 hr
= OLE_CALL_ARGS(chain
->pCapturePin
, EnumMediaTypes
, &pEnum
);
2158 mp_msg(MSGT_TV
, MSGL_DBG4
,
2159 "tvi_dshow: Call to EnumMediaTypes failed (get_available_formats_pin)\n");
2162 for (i
= 0; OLE_CALL_ARGS(pEnum
, Next
, 1, &pmt
, &cFetched
) == S_OK
; i
++) {
2166 OLE_CALL(pEnum
,Reset
);
2170 (AM_MEDIA_TYPE
**) malloc((count
+ 1) * sizeof(AM_MEDIA_TYPE
*));
2172 return E_OUTOFMEMORY
;
2173 memset(arpmt
, 0, (count
+ 1) * sizeof(AM_MEDIA_TYPE
*));
2177 && OLE_CALL_ARGS(pEnum
, Next
, 1, &(arpmt
[i
]), &cFetched
) == S_OK
;
2180 OLE_RELEASE_SAFE(pEnum
);
2183 pBuf
= (void **) malloc((count
+ 1) * sizeof(void *));
2185 for (i
= 0; i
< count
; i
++)
2187 DeleteMediaType(arpmt
[i
]);
2189 return E_OUTOFMEMORY
;
2191 memset(pBuf
, 0, (count
+ 1) * sizeof(void *));
2193 for (i
= 0; i
< count
; i
++) {
2194 pBuf
[i
] = malloc(size
);
2197 memset(pBuf
[i
], 0, size
);
2199 if (chain
->type
== video
) {
2200 pVideoCaps
= (VIDEO_STREAM_CONFIG_CAPS
*) pBuf
[i
];
2201 extract_video_format(arpmt
[i
], NULL
, &p1
, &p2
);
2202 pVideoCaps
->MaxOutputSize
.cx
= pVideoCaps
->MinOutputSize
.cx
=
2204 pVideoCaps
->MaxOutputSize
.cy
= pVideoCaps
->MinOutputSize
.cy
=
2207 pAudioCaps
= (AUDIO_STREAM_CONFIG_CAPS
*) pBuf
[i
];
2208 extract_audio_format(arpmt
[i
], &p1
, &p2
, &p3
);
2209 pAudioCaps
->MaximumSampleFrequency
=
2210 pAudioCaps
->MinimumSampleFrequency
= p1
;
2211 pAudioCaps
->MaximumBitsPerSample
=
2212 pAudioCaps
->MinimumBitsPerSample
= p2
;
2213 pAudioCaps
->MaximumChannels
= pAudioCaps
->MinimumChannels
= p3
;
2218 for (i
= 0; i
< count
; i
++) {
2220 DeleteMediaType(arpmt
[i
]);
2226 return E_OUTOFMEMORY
;
2228 chain
->arpmt
= arpmt
;
2229 chain
->arStreamCaps
= pBuf
;
2235 *---------------------------------------------------------------------------------------
2239 *---------------------------------------------------------------------------------------
2242 * \brief fills given buffer with audio data (usually one block)
2244 * \param priv driver's private data structure
2245 * \param buffer buffer to store data to
2246 * \param len buffer's size in bytes (usually one block size)
2248 * \return audio pts if audio present, 1 - otherwise
2250 static double grab_audio_frame(priv_t
* priv
, char *buffer
, int len
)
2255 grabber_ringbuffer_t
*rb
= priv
->chains
[1]->rbuf
;
2256 grabber_ringbuffer_t
*vrb
= priv
->chains
[0]->rbuf
;
2258 if (!rb
|| !rb
->ringbuffer
)
2261 if(vrb
&& vrb
->tStart
<0){
2262 memset(buffer
,0,len
);
2265 if(vrb
&& rb
->tStart
<0)
2266 rb
->tStart
=vrb
->tStart
;
2268 if (len
< rb
->blocksize
)
2271 bytes
= rb
->blocksize
;
2273 mp_msg(MSGT_TV
, MSGL_DBG3
,"tvi_dshow: FillBuffer (audio) called. %d blocks in buffer, %d bytes requested\n",
2276 mp_msg(MSGT_TV
,MSGL_DBG4
,"tvi_dshow: waiting for frame\n");
2277 for(i
=0;i
<1000 && !rb
->count
;i
++) usec_sleep(1000);
2279 mp_msg(MSGT_TV
,MSGL_DBG4
,"tvi_dshow: waiting timeout\n");
2282 mp_msg(MSGT_TV
,MSGL_DBG4
,"tvi_dshow: got frame!\n");
2285 EnterCriticalSection(rb
->pMutex
);
2286 pts
=rb
->dpts
[rb
->head
]-rb
->tStart
;
2287 memcpy(buffer
, rb
->ringbuffer
[rb
->head
], bytes
);
2288 rb
->head
= (rb
->head
+ 1) % rb
->buffersize
;
2290 LeaveCriticalSection(rb
->pMutex
);
2295 * \brief returns audio frame size
2297 * \param priv driver's private data structure
2299 * \return audio block size if audio enabled and 1 - otherwise
2301 static int get_audio_framesize(priv_t
* priv
)
2303 if (!priv
->chains
[1]->rbuf
)
2304 return 1; //no audio
2305 mp_msg(MSGT_TV
,MSGL_DBG3
,"get_audio_framesize: %d\n",priv
->chains
[1]->rbuf
->blocksize
);
2306 return priv
->chains
[1]->rbuf
->blocksize
;
2309 #ifdef CONFIG_TV_TELETEXT
2310 static int vbi_get_props(priv_t
* priv
,tt_stream_props
* ptsp
)
2313 return TVI_CONTROL_FALSE
;
2319 ptsp
->sampling_rate
=27e6
;
2320 ptsp
->samples_per_line
=720;
2325 ptsp
->bufsize
= ptsp
->samples_per_line
* (ptsp
->count
[0] + ptsp
->count
[1]);
2327 mp_msg(MSGT_TV
,MSGL_V
,"vbi_get_props: sampling_rate=%d,offset:%d,samples_per_line: %d\n interlaced:%s, count=[%d,%d]\n",
2328 ptsp
->sampling_rate
,
2330 ptsp
->samples_per_line
,
2331 ptsp
->interlaced
?"Yes":"No",
2335 return TVI_CONTROL_TRUE
;
2338 static void vbi_grabber(priv_t
* priv
)
2340 grabber_ringbuffer_t
*rb
= priv
->chains
[2]->rbuf
;
2343 if (!rb
|| !rb
->ringbuffer
)
2346 buf
=calloc(1,rb
->blocksize
);
2347 for(i
=0; i
<23 && rb
->count
; i
++){
2348 memcpy(buf
,rb
->ringbuffer
[rb
->head
],rb
->blocksize
);
2349 teletext_control(priv
->priv_vbi
,TV_VBI_CONTROL_DECODE_PAGE
,&buf
);
2350 rb
->head
= (rb
->head
+ 1) % rb
->buffersize
;
2355 #endif /* CONFIG_TV_TELETEXT */
2358 * \brief fills given buffer with video data (usually one frame)
2360 * \param priv driver's private data structure
2361 * \param buffer buffer to store data to
2362 * \param len buffer's size in bytes (usually one frame size)
2364 * \return frame size if video present, 0 - otherwise
2366 static double grab_video_frame(priv_t
* priv
, char *buffer
, int len
)
2371 grabber_ringbuffer_t
*rb
= priv
->chains
[0]->rbuf
;
2373 if (!rb
|| !rb
->ringbuffer
)
2375 if (len
< rb
->blocksize
)
2378 bytes
= rb
->blocksize
;
2380 mp_msg(MSGT_TV
, MSGL_DBG3
,"tvi_dshow: FillBuffer (video) called. %d blocks in buffer, %d bytes requested\n",
2383 mp_msg(MSGT_TV
,MSGL_DBG4
,"tvi_dshow: waiting for frame\n");
2384 for(i
=0;i
<1000 && !rb
->count
;i
++) usec_sleep(1000);
2386 mp_msg(MSGT_TV
,MSGL_DBG4
,"tvi_dshow: waiting timeout\n");
2389 mp_msg(MSGT_TV
,MSGL_DBG4
,"tvi_dshow: got frame!\n");
2391 EnterCriticalSection(rb
->pMutex
);
2393 rb
->tStart
=rb
->dpts
[rb
->head
];
2394 pts
=rb
->dpts
[rb
->head
]-rb
->tStart
;
2395 memcpy(buffer
, rb
->ringbuffer
[rb
->head
], bytes
);
2396 rb
->head
= (rb
->head
+ 1) % rb
->buffersize
;
2398 LeaveCriticalSection(rb
->pMutex
);
2400 #ifdef CONFIG_TV_TELETEXT
2407 * \brief returns frame size
2409 * \param priv driver's private data structure
2411 * \return frame size if video present, 0 - otherwise
2413 static int get_video_framesize(priv_t
* priv
)
2415 // if(!priv->pmtVideo) return 1; //no video
2416 // return priv->pmtVideo->lSampleSize;
2417 if (!priv
->chains
[0]->rbuf
)
2418 return 1; //no video
2419 mp_msg(MSGT_TV
,MSGL_DBG3
,"geT_video_framesize: %d\n",priv
->chains
[0]->rbuf
->blocksize
);
2420 return priv
->chains
[0]->rbuf
->blocksize
;
2424 * \brief calculate audio buffer size
2425 * \param video_buf_size size of video buffer in bytes
2426 * \param video_bitrate video bit rate
2427 * \param audio_bitrate audio bit rate
2428 * \return audio buffer isze in bytes
2430 * \remarks length of video buffer and resulted audio buffer calculated in
2431 * seconds will be the same.
2433 static inline int audio_buf_size_from_video(int video_buf_size
, int video_bitrate
, int audio_bitrate
)
2435 int audio_buf_size
= audio_bitrate
* (video_buf_size
/ video_bitrate
);
2436 mp_msg(MSGT_TV
,MSGL_DBG2
,"tvi_dshow: Audio capture buffer: %d * %d / %d = %d\n",
2437 audio_bitrate
,video_buf_size
,video_bitrate
,audio_buf_size
);
2438 return audio_buf_size
;
2442 * \brief common chain initialization routine
2443 * \param chain chain data structure
2445 * \note pCaptureFilter member should be initialized before call to this routine
2447 static HRESULT
init_chain_common(ICaptureGraphBuilder2
*pBuilder
, chain_t
*chain
)
2452 if(!chain
->pCaptureFilter
)
2455 show_filter_info(chain
->pCaptureFilter
);
2457 hr
= OLE_CALL_ARGS(pBuilder
, FindPin
,
2458 (IUnknown
*) chain
->pCaptureFilter
,
2459 PINDIR_OUTPUT
, chain
->pin_category
,
2460 chain
->majortype
, FALSE
, 0, &chain
->pCapturePin
);
2463 mp_msg(MSGT_TV
,MSGL_DBG2
, "tvi_dshow: FindPin(pCapturePin) call failed. Error:0x%x\n", (unsigned int)hr
);
2467 hr
= OLE_CALL_ARGS(pBuilder
, FindInterface
,
2468 chain
->pin_category
,
2470 chain
->pCaptureFilter
,
2471 &IID_IAMStreamConfig
,
2472 (void **) &(chain
->pStreamConfig
));
2474 chain
->pStreamConfig
= NULL
;
2477 Getting available video formats (last pointer in array will be NULL)
2478 First tryin to call IAMStreamConfig::GetStreamCaos. this will give us additional information such as
2479 min/max picture dimensions, etc. If this call fails trying IPIn::EnumMediaTypes with default
2482 hr
= get_available_formats_stream(chain
);
2484 mp_msg(MSGT_TV
, MSGL_DBG2
, "Unable to use IAMStreamConfig for retriving available formats (Error:0x%x). Using EnumMediaTypes instead\n", (unsigned int)hr
);
2485 hr
= get_available_formats_pin(pBuilder
, chain
);
2490 chain
->nFormatUsed
= 0;
2492 //If argument to CreateMediaType is NULL then result will be NULL too.
2493 chain
->pmt
= CreateMediaType(chain
->arpmt
[0]);
2495 for (i
= 0; chain
->arpmt
[i
]; i
++)
2496 DisplayMediaType("Available format", chain
->arpmt
[i
]);
2501 * \brief build video stream chain in graph
2502 * \param priv private data structure
2504 * \return S_OK if chain was built successfully, apropriate error code otherwise
2506 static HRESULT
build_video_chain(priv_t
*priv
)
2510 if(priv
->chains
[0]->rbuf
)
2513 if (priv
->chains
[0]->pStreamConfig
) {
2514 hr
= OLE_CALL_ARGS(priv
->chains
[0]->pStreamConfig
, SetFormat
, priv
->chains
[0]->pmt
);
2516 mp_msg(MSGT_TV
,MSGL_ERR
,MSGTR_TVI_DS_UnableSelectVideoFormat
, (unsigned int)hr
);
2520 priv
->chains
[0]->rbuf
=calloc(1,sizeof(grabber_ringbuffer_t
));
2521 if(!priv
->chains
[0]->rbuf
)
2522 return E_OUTOFMEMORY
;
2524 if (priv
->tv_param
->buffer_size
>= 0) {
2525 priv
->chains
[0]->rbuf
->buffersize
= priv
->tv_param
->buffer_size
;
2527 priv
->chains
[0]->rbuf
->buffersize
= 16;
2530 priv
->chains
[0]->rbuf
->buffersize
*= 1024 * 1024;
2531 hr
=build_sub_graph(priv
, priv
->chains
[0], &PIN_CATEGORY_CAPTURE
);
2533 mp_msg(MSGT_TV
, MSGL_ERR
, MSGTR_TVI_DS_UnableBuildVideoSubGraph
,(unsigned int)hr
);
2540 * \brief build audio stream chain in graph
2541 * \param priv private data structure
2543 * \return S_OK if chain was built successfully, apropriate error code otherwise
2545 static HRESULT
build_audio_chain(priv_t
*priv
)
2549 if(priv
->chains
[1]->rbuf
)
2552 if(priv
->immediate_mode
)
2555 if (priv
->chains
[1]->pStreamConfig
) {
2556 hr
= OLE_CALL_ARGS(priv
->chains
[1]->pStreamConfig
, SetFormat
,
2557 priv
->chains
[1]->pmt
);
2559 mp_msg(MSGT_TV
,MSGL_ERR
,MSGTR_TVI_DS_UnableSelectAudioFormat
, (unsigned int)hr
);
2563 if(priv
->chains
[1]->pmt
){
2564 priv
->chains
[1]->rbuf
=calloc(1,sizeof(grabber_ringbuffer_t
));
2565 if(!priv
->chains
[1]->rbuf
)
2566 return E_OUTOFMEMORY
;
2568 /* let the audio buffer be the same size (in seconds) than video one */
2569 priv
->chains
[1]->rbuf
->buffersize
=audio_buf_size_from_video(
2570 priv
->chains
[0]->rbuf
->buffersize
,
2571 (((VIDEOINFOHEADER
*) priv
->chains
[0]->pmt
->pbFormat
)->dwBitRate
),
2572 (((WAVEFORMATEX
*) (priv
->chains
[1]->pmt
->pbFormat
))->nAvgBytesPerSec
));
2574 hr
=build_sub_graph(priv
, priv
->chains
[1],&PIN_CATEGORY_CAPTURE
);
2576 mp_msg(MSGT_TV
, MSGL_ERR
, MSGTR_TVI_DS_UnableBuildAudioSubGraph
,(unsigned int)hr
);
2584 * \brief build VBI stream chain in graph
2585 * \param priv private data structure
2587 * \return S_OK if chain was built successfully, apropriate error code otherwise
2589 static HRESULT
build_vbi_chain(priv_t
*priv
)
2591 #ifdef CONFIG_TV_TELETEXT
2594 if(priv
->chains
[2]->rbuf
)
2597 if(priv
->tv_param
->tdevice
)
2599 priv
->chains
[2]->rbuf
=calloc(1,sizeof(grabber_ringbuffer_t
));
2600 if(!priv
->chains
[2]->rbuf
)
2601 return E_OUTOFMEMORY
;
2603 init_ringbuffer(priv
->chains
[2]->rbuf
,24,priv
->tsp
.bufsize
);
2605 hr
=build_sub_graph(priv
, priv
->chains
[2],&PIN_CATEGORY_VBI
);
2607 mp_msg(MSGT_TV
, MSGL_ERR
, MSGTR_TVI_DS_UnableBuildVBISubGraph
,(unsigned int)hr
);
2616 * \brief playback/capture real start
2618 * \param priv driver's private data structure
2620 * \return 1 if success, 0 - otherwise
2622 * TODO: move some code from init() here
2624 static int start(priv_t
* priv
)
2628 hr
= build_video_chain(priv
);
2632 hr
= build_audio_chain(priv
);
2636 hr
= build_vbi_chain(priv
);
2641 Graph is ready to capture. Starting graph.
2643 if (mp_msg_test(MSGT_TV
, MSGL_DBG2
)) {
2644 mp_msg(MSGT_TV
, MSGL_DBG2
, "Debug pause 10sec\n");
2645 usec_sleep(10000000);
2646 mp_msg(MSGT_TV
, MSGL_DBG2
, "Debug pause end\n");
2648 if (!priv
->pMediaControl
) {
2649 mp_msg(MSGT_TV
,MSGL_ERR
,MSGTR_TVI_DS_UnableGetMediaControlInterface
,(unsigned int)E_POINTER
);
2652 hr
= OLE_CALL(priv
->pMediaControl
, Run
);
2654 mp_msg(MSGT_TV
,MSGL_ERR
,MSGTR_TVI_DS_UnableStartGraph
, (unsigned int)hr
);
2657 mp_msg(MSGT_TV
, MSGL_DBG2
, "tvi_dshow: Graph is started.\n");
2664 * \brief driver initialization
2666 * \param priv driver's private data structure
2668 * \return 1 if success, 0 - otherwise
2670 static int init(priv_t
* priv
)
2674 long lInput
, lTunerInput
;
2675 IEnumFilters
*pEnum
;
2676 IBaseFilter
*pFilter
;
2685 priv
->chains
[i
] = calloc(1, sizeof(chain_t
));
2687 priv
->chains
[0]->type
=video
;
2688 priv
->chains
[0]->majortype
=&MEDIATYPE_Video
;
2689 priv
->chains
[0]->pin_category
=&PIN_CATEGORY_CAPTURE
;
2690 priv
->chains
[1]->type
=audio
;
2691 priv
->chains
[1]->majortype
=&MEDIATYPE_Audio
;
2692 priv
->chains
[1]->pin_category
=&PIN_CATEGORY_CAPTURE
;
2693 priv
->chains
[2]->type
=vbi
;
2694 priv
->chains
[2]->majortype
=&MEDIATYPE_VBI
;
2695 priv
->chains
[2]->pin_category
=&PIN_CATEGORY_VBI
;
2698 hr
= CoCreateInstance((GUID
*) & CLSID_FilterGraph
, NULL
,
2699 CLSCTX_INPROC_SERVER
, &IID_IGraphBuilder
,
2700 (void **) &priv
->pGraph
);
2702 mp_msg(MSGT_TV
,MSGL_DBG2
, "tvi_dshow: CoCreateInstance(FilterGraph) call failed. Error:0x%x\n", (unsigned int)hr
);
2706 if (mp_msg_test(MSGT_TV
, MSGL_DBG2
)) {
2707 AddToRot((IUnknown
*) priv
->pGraph
, &(priv
->dwRegister
));
2710 hr
= CoCreateInstance((GUID
*) & CLSID_CaptureGraphBuilder2
, NULL
,
2711 CLSCTX_INPROC_SERVER
, &IID_ICaptureGraphBuilder2
,
2712 (void **) &priv
->pBuilder
);
2714 mp_msg(MSGT_TV
,MSGL_DBG2
, "tvi_dshow: CoCreateInstance(CaptureGraphBuilder) call failed. Error:0x%x\n", (unsigned int)hr
);
2718 hr
= OLE_CALL_ARGS(priv
->pBuilder
, SetFiltergraph
, priv
->pGraph
);
2720 mp_msg(MSGT_TV
,MSGL_ERR
, "tvi_dshow: SetFiltergraph call failed. Error:0x%x\n",(unsigned int)hr
);
2724 mp_msg(MSGT_TV
, MSGL_DBG2
, "tvi_dshow: Searching for available video capture devices\n");
2725 priv
->chains
[0]->pCaptureFilter
= find_capture_device(priv
->dev_index
, &CLSID_VideoInputDeviceCategory
);
2726 if(!priv
->chains
[0]->pCaptureFilter
){
2727 mp_msg(MSGT_TV
,MSGL_ERR
, MSGTR_TVI_DS_NoVideoCaptureDevice
);
2730 hr
= OLE_CALL_ARGS(priv
->pGraph
, AddFilter
, priv
->chains
[0]->pCaptureFilter
, NULL
);
2732 mp_msg(MSGT_TV
, MSGL_DBG2
, "tvi_dshow: Unable to add video capture device to Directshow graph. Error:0x%x\n", (unsigned int)hr
);
2735 mp_msg(MSGT_TV
, MSGL_DBG2
, "tvi_dshow: Searching for available audio capture devices\n");
2736 if (priv
->adev_index
!= -1) {
2737 priv
->chains
[1]->pCaptureFilter
= find_capture_device(priv
->adev_index
, &CLSID_AudioInputDeviceCategory
); //output available audio edevices
2738 if(!priv
->chains
[1]->pCaptureFilter
){
2739 mp_msg(MSGT_TV
,MSGL_ERR
, MSGTR_TVI_DS_NoAudioCaptureDevice
);
2743 hr
= OLE_CALL_ARGS(priv
->pGraph
, AddFilter
, priv
->chains
[1]->pCaptureFilter
, NULL
);
2745 mp_msg(MSGT_TV
,MSGL_DBG2
, "tvi_dshow: Unable to add audio capture device to Directshow graph. Error:0x%x\n", (unsigned int)hr
);
2749 hr
= OLE_QUERYINTERFACE(priv
->chains
[0]->pCaptureFilter
, IID_IBaseFilter
, priv
->chains
[1]->pCaptureFilter
);
2751 /* increase refrence counter for capture filter ad store pointer into vbi chain structure too */
2752 hr
= OLE_QUERYINTERFACE(priv
->chains
[0]->pCaptureFilter
, IID_IBaseFilter
, priv
->chains
[2]->pCaptureFilter
);
2754 hr
= OLE_QUERYINTERFACE(priv
->chains
[0]->pCaptureFilter
, IID_IAMVideoProcAmp
,priv
->pVideoProcAmp
);
2755 if (FAILED(hr
) && hr
!= E_NOINTERFACE
)
2756 mp_msg(MSGT_TV
, MSGL_DBG2
, "tvi_dshow: Get IID_IAMVideoProcAmp failed (0x%x).\n", (unsigned int)hr
);
2759 mp_msg(MSGT_TV
, MSGL_INFO
, MSGTR_TVI_DS_VideoAdjustigNotSupported
);
2760 priv
->pVideoProcAmp
= NULL
;
2763 hr
= OLE_CALL_ARGS(priv
->pBuilder
, FindInterface
,
2764 &PIN_CATEGORY_CAPTURE
,
2765 priv
->chains
[0]->majortype
,
2766 priv
->chains
[0]->pCaptureFilter
,
2767 &IID_IAMCrossbar
, (void **) &(priv
->pCrossbar
));
2769 mp_msg(MSGT_TV
, MSGL_INFO
, MSGTR_TVI_DS_SelectingInputNotSupported
);
2770 priv
->pCrossbar
= NULL
;
2773 if (priv
->tv_param
->amode
>= 0) {
2774 IAMTVAudio
*pTVAudio
;
2775 hr
= OLE_CALL_ARGS(priv
->pBuilder
, FindInterface
, NULL
, NULL
,priv
->chains
[0]->pCaptureFilter
,&IID_IAMTVAudio
, (void *) &pTVAudio
);
2777 switch (priv
->tv_param
->amode
) {
2779 hr
= OLE_CALL_ARGS(pTVAudio
, put_TVAudioMode
, AMTVAUDIO_MODE_MONO
);
2782 hr
= OLE_CALL_ARGS(pTVAudio
, put_TVAudioMode
, AMTVAUDIO_MODE_STEREO
);
2785 hr
= OLE_CALL_ARGS(pTVAudio
, put_TVAudioMode
,
2786 AMTVAUDIO_MODE_LANG_A
);
2789 hr
= OLE_CALL_ARGS(pTVAudio
, put_TVAudioMode
,
2790 AMTVAUDIO_MODE_LANG_B
);
2793 OLE_RELEASE_SAFE(pTVAudio
);
2795 mp_msg(MSGT_TV
, MSGL_WARN
, MSGTR_TVI_DS_UnableSetAudioMode
, priv
->tv_param
->amode
,(unsigned int)hr
);
2799 // Video chain initialization
2800 hr
= init_chain_common(priv
->pBuilder
, priv
->chains
[0]);
2805 Audio chain initialization
2806 Since absent audio stream is not fatal,
2807 at least one NULL pointer should be kept in format arrays
2808 (to avoid another additional check everywhere for array presence).
2810 hr
= init_chain_common(priv
->pBuilder
, priv
->chains
[1]);
2813 mp_msg(MSGT_TV
, MSGL_V
, "tvi_dshow: Unable to initialize audio chain (Error:0x%x). Audio disabled\n", (unsigned long)hr
);
2814 priv
->chains
[1]->arpmt
=calloc(1, sizeof(AM_MEDIA_TYPE
*));
2815 priv
->chains
[1]->arStreamCaps
=calloc(1, sizeof(void*));
2819 VBI chain initialization
2820 Since absent VBI stream is not fatal,
2821 at least one NULL pointer should be kept in format arrays
2822 (to avoid another additional check everywhere for array presence).
2824 hr
= init_chain_common(priv
->pBuilder
, priv
->chains
[2]);
2827 mp_msg(MSGT_TV
, MSGL_V
, "tvi_dshow: Unable to initialize VBI chain (Error:0x%x). Teletext disabled\n", (unsigned long)hr
);
2828 priv
->chains
[2]->arpmt
=calloc(1, sizeof(AM_MEDIA_TYPE
*));
2829 priv
->chains
[2]->arStreamCaps
=calloc(1, sizeof(void*));
2832 if (!priv
->chains
[0]->pStreamConfig
)
2833 mp_msg(MSGT_TV
, MSGL_INFO
, MSGTR_TVI_DS_ChangingWidthHeightNotSupported
);
2835 if (!priv
->chains
[0]->arpmt
[priv
->chains
[0]->nFormatUsed
]
2836 || !extract_video_format(priv
->chains
[0]->arpmt
[priv
->chains
[0]->nFormatUsed
],
2837 &(priv
->fcc
), &(priv
->width
),
2839 mp_msg(MSGT_TV
, MSGL_ERR
, MSGTR_TVI_DS_ErrorParsingVideoFormatStruct
);
2843 if (priv
->chains
[1]->arpmt
[priv
->chains
[1]->nFormatUsed
]) {
2844 if (!extract_audio_format(priv
->chains
[1]->pmt
, &(priv
->samplerate
), NULL
, NULL
)) {
2845 mp_msg(MSGT_TV
, MSGL_ERR
, MSGTR_TVI_DS_ErrorParsingAudioFormatStruct
);
2846 DisplayMediaType("audio format failed",priv
->chains
[1]->arpmt
[priv
->chains
[1]->nFormatUsed
]);
2851 hr
= OLE_QUERYINTERFACE(priv
->pGraph
, IID_IMediaControl
,priv
->pMediaControl
);
2853 mp_msg(MSGT_TV
,MSGL_ERR
, MSGTR_TVI_DS_UnableGetMediaControlInterface
,(unsigned int)hr
);
2856 hr
= OLE_CALL_ARGS(priv
->pBuilder
, FindInterface
,
2857 &PIN_CATEGORY_CAPTURE
, NULL
,
2858 priv
->chains
[0]->pCaptureFilter
,
2859 &IID_IAMTVTuner
, (void **) &(priv
->pTVTuner
));
2861 if (!priv
->pTVTuner
) {
2862 mp_msg(MSGT_TV
, MSGL_DBG2
, "tvi_dshow: Unable to access IAMTVTuner (0x%x)\n", (unsigned int)hr
);
2865 // shows Tuner capabilities
2866 get_capabilities(priv
);
2868 if (priv
->pTVTuner
) {
2869 hr
= OLE_CALL_ARGS(priv
->pTVTuner
, put_CountryCode
,
2870 chanlist2country(priv
->tv_param
->chanlist
));
2872 mp_msg(MSGT_TV
,MSGL_DBG2
, "tvi_dshow: Call to put_CountryCode failed. Error:0x%x\n",(unsigned int)hr
);
2875 hr
= OLE_CALL_ARGS(priv
->pTVTuner
, put_Mode
, AMTUNER_MODE_TV
);
2877 mp_msg(MSGT_TV
,MSGL_DBG2
, "tvi_dshow: Call to put_Mode failed. Error:0x%x\n",(unsigned int)hr
);
2881 hr
= OLE_CALL_ARGS(priv
->pTVTuner
, get_ConnectInput
, &lInput
);
2883 mp_msg(MSGT_TV
,MSGL_DBG2
, "tvi_dshow: Call to get_ConnectInput failed. Error:0x%x\n",(unsigned int)hr
);
2888 lTunerInput
= strstr(priv
->tv_param
->chanlist
, "cable") ? TunerInputCable
: TunerInputAntenna
;
2890 hr
= OLE_CALL_ARGS(priv
->pTVTuner
, put_InputType
, lInput
, lTunerInput
);
2892 mp_msg(MSGT_TV
,MSGL_DBG2
, "tvi_dshow: Call to put_InputType failed. Error:0x%x\n",(unsigned int)hr
);
2899 for VIVO cards we should check if preview pin is available on video capture device.
2900 If it is not, we have to connect Video Port Manager filter to VP pin of capture device filter.
2901 Otherwise we will get 0x8007001f (Device is not functioning properly) when attempting to start graph
2903 hr
= OLE_CALL_ARGS(priv
->pBuilder
, FindPin
,
2904 (IUnknown
*) priv
->chains
[0]->pCaptureFilter
,
2906 &PIN_CATEGORY_VIDEOPORT
, NULL
, FALSE
,
2907 0, (IPin
**) & pVPOutPin
);
2908 if (SUCCEEDED(hr
)) {
2909 hr
= OLE_CALL_ARGS(priv
->pGraph
, Render
, pVPOutPin
);
2910 OLE_RELEASE_SAFE(pVPOutPin
);
2913 mp_msg(MSGT_TV
,MSGL_ERR
, MSGTR_TVI_DS_UnableTerminateVPPin
, (unsigned int)hr
);
2918 OLE_CALL_ARGS(priv
->pGraph
, EnumFilters
, &pEnum
);
2919 while (OLE_CALL_ARGS(pEnum
, Next
, 1, &pFilter
, NULL
) == S_OK
) {
2920 LPVIDEOWINDOW pVideoWindow
;
2921 hr
= OLE_QUERYINTERFACE(pFilter
, IID_IVideoWindow
, pVideoWindow
);
2924 if(priv
->tv_param
->hidden_vp_renderer
){
2925 OLE_CALL_ARGS(pVideoWindow
,put_Visible
,/* OAFALSE*/ 0);
2926 OLE_CALL_ARGS(pVideoWindow
,put_AutoShow
,/* OAFALSE*/ 0);
2929 OLE_CALL_ARGS(priv
->pGraph
, RemoveFilter
, pFilter
);
2931 OLE_RELEASE_SAFE(pVideoWindow
);
2933 OLE_RELEASE_SAFE(pFilter
);
2935 OLE_RELEASE_SAFE(pEnum
);
2936 if(priv
->tv_param
->system_clock
)
2938 LPREFERENCECLOCK rc
;
2940 hr
= CoCreateInstance((GUID
*) & CLSID_SystemClock
, NULL
,
2941 CLSCTX_INPROC_SERVER
, &IID_IReferenceClock
,
2944 OLE_QUERYINTERFACE(priv
->pBuilder
,IID_IBaseFilter
,pBF
);
2945 OLE_CALL_ARGS(pBF
,SetSyncSource
,rc
);
2947 #ifdef CONFIG_TV_TELETEXT
2948 if(vbi_get_props(priv
,&(priv
->tsp
))!=TVI_CONTROL_TRUE
)
2955 mp_msg(MSGT_TV
,MSGL_ERR
, MSGTR_TVI_DS_GraphInitFailure
);
2962 * \brief chain uninitialization
2963 * \param chain chain data structure
2965 static void destroy_chain(chain_t
*chain
)
2972 OLE_RELEASE_SAFE(chain
->pStreamConfig
);
2973 OLE_RELEASE_SAFE(chain
->pCaptureFilter
);
2974 OLE_RELEASE_SAFE(chain
->pCSGCB
);
2975 OLE_RELEASE_SAFE(chain
->pCapturePin
);
2976 OLE_RELEASE_SAFE(chain
->pSGIn
);
2977 OLE_RELEASE_SAFE(chain
->pSG
);
2978 OLE_RELEASE_SAFE(chain
->pSGF
);
2981 DeleteMediaType(chain
->pmt
);
2984 for (i
= 0; chain
->arpmt
[i
]; i
++) {
2985 DeleteMediaType(chain
->arpmt
[i
]);
2990 if (chain
->arStreamCaps
) {
2991 for (i
= 0; chain
->arStreamCaps
[i
]; i
++) {
2992 free(chain
->arStreamCaps
[i
]);
2994 free(chain
->arStreamCaps
);
2998 destroy_ringbuffer(chain
->rbuf
);
3005 * \brief driver uninitialization
3007 * \param priv driver's private data structure
3011 static int uninit(priv_t
* priv
)
3017 if (priv
->dwRegister
) {
3018 RemoveFromRot(priv
->dwRegister
);
3020 #ifdef CONFIG_TV_TELETEXT
3021 teletext_control(priv
->priv_vbi
,TV_VBI_CONTROL_STOP
,(void*)1);
3023 //stop audio grabber thread
3025 if (priv
->state
&& priv
->pMediaControl
) {
3026 OLE_CALL(priv
->pMediaControl
, Stop
);
3028 OLE_RELEASE_SAFE(priv
->pMediaControl
);
3032 if (priv
->chains
[0]->pCaptureFilter
)
3033 OLE_CALL_ARGS(priv
->pGraph
, RemoveFilter
, priv
->chains
[0]->pCaptureFilter
);
3034 if (priv
->chains
[1]->pCaptureFilter
)
3035 OLE_CALL_ARGS(priv
->pGraph
, RemoveFilter
, priv
->chains
[1]->pCaptureFilter
);
3037 OLE_RELEASE_SAFE(priv
->pCrossbar
);
3038 OLE_RELEASE_SAFE(priv
->pVideoProcAmp
);
3039 OLE_RELEASE_SAFE(priv
->pGraph
);
3040 OLE_RELEASE_SAFE(priv
->pBuilder
);
3041 if(priv
->freq_table
){
3042 priv
->freq_table_len
=-1;
3043 free(priv
->freq_table
);
3044 priv
->freq_table
=NULL
;
3049 destroy_chain(priv
->chains
[i
]);
3050 priv
->chains
[i
] = NULL
;
3057 * \brief driver pre-initialization
3059 * \param device string, containing device name in form "x[.y]", where x is video capture device
3060 * (default: 0, first available); y (if given) sets audio capture device
3062 * \return 1 if success,0 - otherwise
3064 static tvi_handle_t
*tvi_init_dshow(tv_param_t
* tv_param
)
3076 memset(priv
, 0, sizeof(priv_t
));
3077 priv
->direct_setfreq_call
= 1; //first using direct call. if it fails, workaround will be enabled
3078 priv
->direct_getfreq_call
= 1; //first using direct call. if it fails, workaround will be enabled
3079 priv
->adev_index
= -1;
3080 priv
->freq_table_len
=-1;
3081 priv
->tv_param
=tv_param
;
3083 if (tv_param
->device
) {
3084 if (sscanf(tv_param
->device
, "%d", &a
) == 1) {
3085 priv
->dev_index
= a
;
3087 mp_msg(MSGT_TV
, MSGL_ERR
, MSGTR_TVI_DS_WrongDeviceParam
, tv_param
->device
);
3091 if (priv
->dev_index
< 0) {
3092 mp_msg(MSGT_TV
, MSGL_ERR
, MSGTR_TVI_DS_WrongDeviceIndex
, a
);
3097 if (tv_param
->adevice
) {
3098 if (sscanf(tv_param
->adevice
, "%d", &a
) == 1) {
3099 priv
->adev_index
= a
;
3101 mp_msg(MSGT_TV
, MSGL_ERR
, MSGTR_TVI_DS_WrongADeviceParam
, tv_param
->adevice
);
3105 if (priv
->dev_index
< 0) {
3106 mp_msg(MSGT_TV
, MSGL_ERR
, MSGTR_TVI_DS_WrongADeviceIndex
, a
);
3115 * \brief driver's ioctl handler
3117 * \param priv driver's private data structure
3118 * \param cmd ioctl command
3119 * \param arg ioct command's parameter
3121 * \return TVI_CONTROL_TRUE if success
3122 * \return TVI_CONTROL_FALSE if failure
3123 * \return TVI_CONTROL_UNKNOWN if unknowm cmd called
3125 static int control(priv_t
* priv
, int cmd
, void *arg
)
3129 case TVI_CONTROL_VID_SET_FORMAT
:
3133 int result
= TVI_CONTROL_TRUE
;
3136 return TVI_CONTROL_FALSE
;
3139 if(!priv
->chains
[0]->arpmt
)
3140 return TVI_CONTROL_FALSE
;
3141 for (i
= 0; priv
->chains
[0]->arpmt
[i
]; i
++)
3142 if (check_video_format
3143 (priv
->chains
[0]->arpmt
[i
], fcc
, priv
->width
, priv
->height
))
3145 if (!priv
->chains
[0]->arpmt
[i
])
3148 VIDEOINFOHEADER
* Vhdr
= NULL
;
3151 mp_msg(MSGT_TV
, MSGL_V
, "tvi_dshow: will try also use undeclared video format: %dx%d, %s\n",priv
->width
, priv
->height
, vo_format_name(fcc
));
3153 if (priv
->chains
[0]->arpmt
[0])
3154 Vhdr
= (VIDEOINFOHEADER
*) priv
->chains
[0]->arpmt
[0]->pbFormat
;
3156 if(Vhdr
&& Vhdr
->bmiHeader
.biSizeImage
)
3157 fps
= Vhdr
->dwBitRate
/ (8 * Vhdr
->bmiHeader
.biSizeImage
);
3159 pmt
=create_video_format(fcc
, priv
->width
, priv
->height
, fps
);
3162 mp_msg(MSGT_TV
, MSGL_V
, "tvi_dshow: Unable to create AM_MEDIA_TYPE structure for given format\n");
3163 return TVI_CONTROL_FALSE
;
3165 priv
->chains
[0]->arpmt
=realloc(priv
->chains
[0]->arpmt
, (i
+2)*sizeof(AM_MEDIA_TYPE
*));
3166 priv
->chains
[0]->arpmt
[i
+1] = NULL
;
3167 priv
->chains
[0]->arpmt
[i
] = pmt
;
3169 priv
->chains
[0]->arStreamCaps
=realloc(priv
->chains
[0]->arStreamCaps
, (i
+2)*sizeof(void*));
3170 priv
->chains
[0]->arpmt
[i
+1] = NULL
;
3172 result
= TVI_CONTROL_FALSE
;
3176 tmp
=priv
->chains
[0]->arpmt
[i
];
3177 tmp2
=priv
->chains
[0]->arStreamCaps
[i
];
3180 priv
->chains
[0]->arpmt
[j
] = priv
->chains
[0]->arpmt
[j
-1];
3181 priv
->chains
[0]->arStreamCaps
[j
] = priv
->chains
[0]->arStreamCaps
[j
-1];
3183 priv
->chains
[0]->arpmt
[0] = tmp
;
3184 priv
->chains
[0]->arStreamCaps
[0] = tmp2
;
3186 priv
->chains
[0]->nFormatUsed
= 0;
3188 if (priv
->chains
[0]->pmt
)
3189 DeleteMediaType(priv
->chains
[0]->pmt
);
3190 priv
->chains
[0]->pmt
=
3191 CreateMediaType(priv
->chains
[0]->arpmt
[priv
->chains
[0]->nFormatUsed
]);
3192 DisplayMediaType("VID_SET_FORMAT", priv
->chains
[0]->pmt
);
3194 Setting width & height to preferred by driver values
3196 extract_video_format(priv
->chains
[0]->arpmt
[priv
->chains
[0]->nFormatUsed
],
3197 &(priv
->fcc
), &(priv
->width
),
3201 case TVI_CONTROL_VID_GET_FORMAT
:
3203 if(!priv
->chains
[0]->pmt
)
3204 return TVI_CONTROL_FALSE
;
3206 Build video chain (for video format negotiation).
3207 If this was done before, routine will do nothing.
3209 build_video_chain(priv
);
3210 DisplayMediaType("VID_GET_FORMAT", priv
->chains
[0]->pmt
);
3212 *(int *) arg
= priv
->fcc
;
3213 return TVI_CONTROL_TRUE
;
3215 return TVI_CONTROL_FALSE
;
3217 case TVI_CONTROL_VID_SET_WIDTH
:
3219 VIDEO_STREAM_CONFIG_CAPS
*pCaps
;
3220 VIDEOINFOHEADER
*Vhdr
;
3221 int width
= *(int *) arg
;
3223 return TVI_CONTROL_FALSE
;
3225 pCaps
= priv
->chains
[0]->arStreamCaps
[priv
->chains
[0]->nFormatUsed
];
3227 return TVI_CONTROL_FALSE
;
3228 if (width
< pCaps
->MinOutputSize
.cx
3229 || width
> pCaps
->MaxOutputSize
.cx
)
3230 return TVI_CONTROL_FALSE
;
3232 if (width
% pCaps
->OutputGranularityX
)
3233 return TVI_CONTROL_FALSE
;
3235 if (!priv
->chains
[0]->pmt
|| !priv
->chains
[0]->pmt
->pbFormat
)
3236 return TVI_CONTROL_FALSE
;
3237 Vhdr
= (VIDEOINFOHEADER
*) priv
->chains
[0]->pmt
->pbFormat
;
3238 Vhdr
->bmiHeader
.biWidth
= width
;
3239 priv
->chains
[0]->pmt
->lSampleSize
= Vhdr
->bmiHeader
.biSizeImage
=
3240 labs(Vhdr
->bmiHeader
.biBitCount
* Vhdr
->bmiHeader
.biWidth
*
3241 Vhdr
->bmiHeader
.biHeight
) >> 3;
3243 priv
->width
= width
;
3245 return TVI_CONTROL_TRUE
;
3247 case TVI_CONTROL_VID_GET_WIDTH
:
3250 *(int *) arg
= priv
->width
;
3251 return TVI_CONTROL_TRUE
;
3253 return TVI_CONTROL_FALSE
;
3255 case TVI_CONTROL_VID_CHK_WIDTH
:
3257 VIDEO_STREAM_CONFIG_CAPS
*pCaps
;
3258 int width
= *(int *) arg
;
3259 pCaps
= priv
->chains
[0]->arStreamCaps
[priv
->chains
[0]->nFormatUsed
];
3261 return TVI_CONTROL_FALSE
;
3262 if (width
< pCaps
->MinOutputSize
.cx
3263 || width
> pCaps
->MaxOutputSize
.cx
)
3264 return TVI_CONTROL_FALSE
;
3266 if (width
% pCaps
->OutputGranularityX
)
3267 return TVI_CONTROL_FALSE
;
3268 return TVI_CONTROL_TRUE
;
3270 case TVI_CONTROL_VID_SET_HEIGHT
:
3272 VIDEO_STREAM_CONFIG_CAPS
*pCaps
;
3273 VIDEOINFOHEADER
*Vhdr
;
3274 int height
= *(int *) arg
;
3276 return TVI_CONTROL_FALSE
;
3278 pCaps
= priv
->chains
[0]->arStreamCaps
[priv
->chains
[0]->nFormatUsed
];
3280 return TVI_CONTROL_FALSE
;
3281 if (height
< pCaps
->MinOutputSize
.cy
3282 || height
> pCaps
->MaxOutputSize
.cy
)
3283 return TVI_CONTROL_FALSE
;
3285 if (height
% pCaps
->OutputGranularityY
)
3286 return TVI_CONTROL_FALSE
;
3288 if (!priv
->chains
[0]->pmt
|| !priv
->chains
[0]->pmt
->pbFormat
)
3289 return TVI_CONTROL_FALSE
;
3290 Vhdr
= (VIDEOINFOHEADER
*) priv
->chains
[0]->pmt
->pbFormat
;
3292 if (Vhdr
->bmiHeader
.biHeight
< 0)
3293 Vhdr
->bmiHeader
.biHeight
= -height
;
3295 Vhdr
->bmiHeader
.biHeight
= height
;
3296 priv
->chains
[0]->pmt
->lSampleSize
= Vhdr
->bmiHeader
.biSizeImage
=
3297 labs(Vhdr
->bmiHeader
.biBitCount
* Vhdr
->bmiHeader
.biWidth
*
3298 Vhdr
->bmiHeader
.biHeight
) >> 3;
3300 priv
->height
= height
;
3301 return TVI_CONTROL_TRUE
;
3303 case TVI_CONTROL_VID_GET_HEIGHT
:
3306 *(int *) arg
= priv
->height
;
3307 return TVI_CONTROL_TRUE
;
3309 return TVI_CONTROL_FALSE
;
3311 case TVI_CONTROL_VID_CHK_HEIGHT
:
3313 VIDEO_STREAM_CONFIG_CAPS
*pCaps
;
3314 int height
= *(int *) arg
;
3315 pCaps
= priv
->chains
[0]->arStreamCaps
[priv
->chains
[0]->nFormatUsed
];
3317 return TVI_CONTROL_FALSE
;
3318 if (height
< pCaps
->MinOutputSize
.cy
3319 || height
> pCaps
->MaxOutputSize
.cy
)
3320 return TVI_CONTROL_FALSE
;
3322 if (height
% pCaps
->OutputGranularityY
)
3323 return TVI_CONTROL_FALSE
;
3325 return TVI_CONTROL_TRUE
;
3327 case TVI_CONTROL_IS_AUDIO
:
3328 if (!priv
->chains
[1]->pmt
)
3329 return TVI_CONTROL_FALSE
;
3331 return TVI_CONTROL_TRUE
;
3332 case TVI_CONTROL_IS_VIDEO
:
3333 return TVI_CONTROL_TRUE
;
3334 case TVI_CONTROL_AUD_GET_FORMAT
:
3336 *(int *) arg
= AF_FORMAT_S16_LE
;
3337 if (!priv
->chains
[1]->pmt
)
3338 return TVI_CONTROL_FALSE
;
3340 return TVI_CONTROL_TRUE
;
3342 case TVI_CONTROL_AUD_GET_CHANNELS
:
3344 *(int *) arg
= priv
->channels
;
3345 if (!priv
->chains
[1]->pmt
)
3346 return TVI_CONTROL_FALSE
;
3348 return TVI_CONTROL_TRUE
;
3350 case TVI_CONTROL_AUD_SET_SAMPLERATE
:
3354 return TVI_CONTROL_FALSE
;
3355 if (!priv
->chains
[1]->arpmt
[0])
3356 return TVI_CONTROL_FALSE
;
3358 samplerate
= *(int *) arg
;;
3360 for (i
= 0; priv
->chains
[1]->arpmt
[i
]; i
++)
3361 if (check_audio_format
3362 (priv
->chains
[1]->arpmt
[i
], samplerate
, 16, priv
->channels
))
3364 if (!priv
->chains
[1]->arpmt
[i
]) {
3365 //request not found. failing back to first available
3366 mp_msg(MSGT_TV
, MSGL_WARN
, MSGTR_TVI_DS_SamplerateNotsupported
, samplerate
);
3369 if (priv
->chains
[1]->pmt
)
3370 DeleteMediaType(priv
->chains
[1]->pmt
);
3371 priv
->chains
[1]->pmt
= CreateMediaType(priv
->chains
[1]->arpmt
[i
]);
3372 extract_audio_format(priv
->chains
[1]->arpmt
[i
], &(priv
->samplerate
),
3373 NULL
, &(priv
->channels
));
3374 return TVI_CONTROL_TRUE
;
3376 case TVI_CONTROL_AUD_GET_SAMPLERATE
:
3378 *(int *) arg
= priv
->samplerate
;
3379 if (!priv
->samplerate
)
3380 return TVI_CONTROL_FALSE
;
3381 if (!priv
->chains
[1]->pmt
)
3382 return TVI_CONTROL_FALSE
;
3384 return TVI_CONTROL_TRUE
;
3386 case TVI_CONTROL_AUD_GET_SAMPLESIZE
:
3389 if (!priv
->chains
[1]->pmt
)
3390 return TVI_CONTROL_FALSE
;
3391 if (!priv
->chains
[1]->pmt
->pbFormat
)
3392 return TVI_CONTROL_FALSE
;
3393 pWF
= (WAVEFORMATEX
*) priv
->chains
[1]->pmt
->pbFormat
;
3394 *(int *) arg
= pWF
->wBitsPerSample
/ 8;
3395 return TVI_CONTROL_TRUE
;
3397 case TVI_CONTROL_IS_TUNER
:
3399 if (!priv
->pTVTuner
)
3400 return TVI_CONTROL_FALSE
;
3402 return TVI_CONTROL_TRUE
;
3404 case TVI_CONTROL_TUN_SET_NORM
:
3406 IAMAnalogVideoDecoder
*pVD
;
3413 if (i
< 0 || i
>= tv_available_norms_count
)
3414 return TVI_CONTROL_FALSE
;
3415 lAnalogFormat
= tv_norms
[tv_available_norms
[i
]].index
;
3417 hr
= OLE_QUERYINTERFACE(priv
->chains
[0]->pCaptureFilter
,IID_IAMAnalogVideoDecoder
, pVD
);
3419 return TVI_CONTROL_FALSE
;
3420 hr
= OLE_CALL_ARGS(pVD
, put_TVFormat
, lAnalogFormat
);
3421 OLE_RELEASE_SAFE(pVD
);
3423 return TVI_CONTROL_FALSE
;
3425 return TVI_CONTROL_TRUE
;
3427 case TVI_CONTROL_TUN_GET_NORM
:
3432 IAMAnalogVideoDecoder
*pVD
;
3434 hr
= OLE_QUERYINTERFACE(priv
->chains
[0]->pCaptureFilter
,IID_IAMAnalogVideoDecoder
, pVD
);
3436 hr
= OLE_CALL_ARGS(pVD
, get_TVFormat
, &lAnalogFormat
);
3437 OLE_RELEASE_SAFE(pVD
);
3440 if (FAILED(hr
)) { //trying another method
3441 if (!priv
->pTVTuner
)
3442 return TVI_CONTROL_FALSE
;
3443 hr
=OLE_CALL_ARGS(priv
->pTVTuner
, get_TVFormat
, &lAnalogFormat
);
3445 return TVI_CONTROL_FALSE
;
3447 for (i
= 0; i
< tv_available_norms_count
; i
++) {
3448 if (tv_norms
[tv_available_norms
[i
]].index
== lAnalogFormat
) {
3449 *(int *) arg
= i
+ 1;
3450 return TVI_CONTROL_TRUE
;
3453 return TVI_CONTROL_FALSE
;
3455 case TVI_CONTROL_SPC_GET_NORMID
:
3458 if (!priv
->pTVTuner
)
3459 return TVI_CONTROL_FALSE
;
3460 for (i
= 0; i
< tv_available_norms_count
; i
++) {
3462 (tv_norms
[tv_available_norms
[i
]].name
, (char *) arg
)) {
3463 *(int *) arg
= i
+ 1;
3464 return TVI_CONTROL_TRUE
;
3467 return TVI_CONTROL_FALSE
;
3469 case TVI_CONTROL_SPC_SET_INPUT
:
3471 return set_crossbar_input(priv
, *(int *) arg
);
3473 case TVI_CONTROL_TUN_GET_FREQ
:
3475 unsigned long lFreq
;
3477 if (!priv
->pTVTuner
)
3478 return TVI_CONTROL_FALSE
;
3480 ret
= get_frequency(priv
, &lFreq
);
3481 lFreq
= lFreq
* 16 / 1000000; //convert from Hz to 1/16 MHz units
3483 *(unsigned long *) arg
= lFreq
;
3486 case TVI_CONTROL_TUN_SET_FREQ
:
3488 unsigned long nFreq
= *(unsigned long *) arg
;
3489 if (!priv
->pTVTuner
)
3490 return TVI_CONTROL_FALSE
;
3492 nFreq
= 1000000 * nFreq
/ 16; //convert from 1/16 MHz units to Hz
3493 return set_frequency(priv
, nFreq
);
3495 case TVI_CONTROL_VID_SET_HUE
:
3496 return set_control(priv
, VideoProcAmp_Hue
, *(int *) arg
);
3497 case TVI_CONTROL_VID_GET_HUE
:
3498 return get_control(priv
, VideoProcAmp_Hue
, (int *) arg
);
3499 case TVI_CONTROL_VID_SET_CONTRAST
:
3500 return set_control(priv
, VideoProcAmp_Contrast
, *(int *) arg
);
3501 case TVI_CONTROL_VID_GET_CONTRAST
:
3502 return get_control(priv
, VideoProcAmp_Contrast
, (int *) arg
);
3503 case TVI_CONTROL_VID_SET_SATURATION
:
3504 return set_control(priv
, VideoProcAmp_Saturation
, *(int *) arg
);
3505 case TVI_CONTROL_VID_GET_SATURATION
:
3506 return get_control(priv
, VideoProcAmp_Saturation
, (int *) arg
);
3507 case TVI_CONTROL_VID_SET_BRIGHTNESS
:
3508 return set_control(priv
, VideoProcAmp_Brightness
, *(int *) arg
);
3509 case TVI_CONTROL_VID_GET_BRIGHTNESS
:
3510 return get_control(priv
, VideoProcAmp_Brightness
, (int *) arg
);
3512 case TVI_CONTROL_VID_GET_FPS
:
3514 VIDEOINFOHEADER
*Vhdr
;
3515 if (!priv
->chains
[0]->pmt
)
3516 return TVI_CONTROL_FALSE
;
3517 if (!priv
->chains
[0]->pmt
->pbFormat
)
3518 return TVI_CONTROL_FALSE
;
3519 Vhdr
= (VIDEOINFOHEADER
*) priv
->chains
[0]->pmt
->pbFormat
;
3521 (1.0 * Vhdr
->dwBitRate
) / (Vhdr
->bmiHeader
.biSizeImage
* 8);
3522 return TVI_CONTROL_TRUE
;
3524 case TVI_CONTROL_IMMEDIATE
:
3525 priv
->immediate_mode
= 1;
3526 return TVI_CONTROL_TRUE
;
3527 #ifdef CONFIG_TV_TELETEXT
3528 case TVI_CONTROL_VBI_INIT
:
3532 if(teletext_control(NULL
,TV_VBI_CONTROL_START
,&ptr
)==TVI_CONTROL_TRUE
)
3535 priv
->priv_vbi
=NULL
;
3536 return TVI_CONTROL_TRUE
;
3539 return teletext_control(priv
->priv_vbi
,cmd
,arg
);
3542 return TVI_CONTROL_UNKNOWN
;