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 * -------------------------------------------------------------------------------
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
25 * -------------------------------------------------------------------------------
28 * WARNING: This is alpha code!
31 * * Watching TV under Win32 using WDM Capture driver and DirectShow
32 * * Grabbing synchronized audio/video with mencoder (synchronization is beeing done by DirectShow)
33 * * If device driver provides IAMStreamConfig interface, user can choose width/height with "-tv height=<h>:width=<w>"
34 * * Adjusting BRIGHTNESS,HUE,SATURATION,CONTRAST if supported by device
35 * * Selecting Tuner,S-Video,... as media source
36 * * User can select used video capture device, passing -tv device=<dev#>
37 * * User can select used audio input, passing -tv audioid=<input#>
39 * options which will not be implemented (probably sometime in future, if possible):
42 * * decimation=<1|2|4>
46 * * [volume|bass|treble|balance]
49 * - LifeView FlyTV Prime 34FM (SAA7134 based) with driver from Ivan Uskov
50 * Partially works with:
51 * - ATI 9200 VIVO based card
56 * * stream goes with 24.93 FPS (NTSC), while reporting 25 FPS (PAL) ?!
57 * * direct set frequency call does not work ('Insufficient Buffer' error)
58 * * audio stream goes with about 1 sample/sec rate when capturing sound from audio card
61 * * check audio with small buffer on vivo !!!
62 * * norm for IAMVideoDecoder and for IAMTVtuner - differs !!
63 * * check how to change TVFormat on VIVO card without tuner
64 * * Flip image upside-down for RGB formats.
66 * * remove debug sleep()
67 * * Add some notes to methods' parameters
68 * * refactor console messages
69 * * check using header files and keep only needed
70 * * add additional comments to methods' bodies
75 /// \ingroup tvi_dshow
80 #include "libmpcodecs/img_format.h"
81 #include "libaf/af_format.h"
83 #include "osdep/timer.h"
88 #include "frequencies.h"
91 #include "tvi_dshow.h"
93 static tvi_handle_t
*tvi_init_dshow(tv_param_t
* tv_param
);
96 *---------------------------------------------------------------------------------------
100 *---------------------------------------------------------------------------------------
103 information about this file
105 tvi_info_t tvi_info_dshow
= {
109 "Vladimir Voroshilov",
110 "Very experimental!! Use with caution"
115 ringbuffer related info
118 CRITICAL_SECTION
*pMutex
; ///< pointer to critical section (mutex)
119 char **ringbuffer
; ///< ringbuffer array
120 double*dpts
; ///< samples' timestamps
122 int buffersize
; ///< size of buffer in blocks
123 int blocksize
; ///< size of individual block
124 int head
; ///< index of first valid sample
125 int tail
; ///< index of last valid sample
126 int count
; ///< count of valid samples in ringbuffer
127 double tStart
; ///< pts of first sample (first sample should have pts 0)
128 } grabber_ringbuffer_t
;
130 typedef enum { unknown
, video
, audio
, vbi
} stream_type
;
133 CSampleGrabberCD definition
135 typedef struct CSampleGrabberCB
{
136 ISampleGrabberCBVtbl
*lpVtbl
;
139 grabber_ringbuffer_t
*pbuf
;
143 Chain related structure
146 stream_type type
; ///< stream type
147 const GUID
* majortype
; ///< GUID of major mediatype (video/audio/vbi)
148 const GUID
* pin_category
; ///< pin category (pointer to one of PIN_CATEGORY_*)
150 IBaseFilter
*pCaptureFilter
; ///< capture device filter
151 IAMStreamConfig
*pStreamConfig
; ///< for configuring stream
152 ISampleGrabber
*pSG
; ///< ISampleGrabber interface of SampleGrabber filter
153 IBaseFilter
*pSGF
; ///< IBaseFilter interface of SampleGrabber filter
154 IPin
*pCapturePin
; ///< output capture pin
155 IPin
*pSGIn
; ///< input pin of SampleGrabber filter
157 grabber_ringbuffer_t
*rbuf
; ///< sample frabber data
158 CSampleGrabberCB
* pCSGCB
; ///< callback object
160 AM_MEDIA_TYPE
*pmt
; ///< stream properties.
161 int nFormatUsed
; ///< index of used format
162 AM_MEDIA_TYPE
**arpmt
; ///< available formats
163 void** arStreamCaps
; ///< VIDEO_STREAM_CONFIG_CAPS or AUDIO_STREAM_CONFIG_CAPS
167 int dev_index
; ///< capture device index in device list (defaul: 0, first available device)
168 int adev_index
; ///< audio capture device index in device list (default: -1, not used)
169 int immediate_mode
; ///< immediate mode (no sound capture)
170 int state
; ///< state: 1-filter graph running, 0-filter graph stopped
171 int direct_setfreq_call
; ///< 0-find nearest channels from system channel list(workaround),1-direct call to set frequency
172 int direct_getfreq_call
; ///< 0-find frequncy from frequency table (workaround),1-direct call to get frequency
174 int fcc
; ///< used video format code (FourCC)
175 int width
; ///< picture width (default: auto)
176 int height
; ///< picture height (default: auto)
178 int channels
; ///< number of audio channels (default: auto)
179 int samplerate
; ///< audio samplerate (default: auto)
181 long *freq_table
; ///< frequency table (in Hz)
182 int freq_table_len
; ///< length of freq table
183 int first_channel
; ///< channel number of first entry in freq table
184 int input
; ///< used input
186 chain_t
* chains
[3]; ///< chains' data (0-video, 1-audio, 2-vbi)
188 IAMTVTuner
*pTVTuner
; ///< interface for tuner device
189 IGraphBuilder
*pGraph
; ///< filter graph
190 ICaptureGraphBuilder2
*pBuilder
; ///< graph builder
191 IMediaControl
*pMediaControl
; ///< interface for controlling graph (start, stop,...)
192 IAMVideoProcAmp
*pVideoProcAmp
; ///< for adjusting hue,saturation,etc
193 IAMCrossbar
*pCrossbar
; ///< for selecting input (Tuner,Composite,S-Video,...)
194 DWORD dwRegister
; ///< allow graphedit to connect to our graph
195 void *priv_vbi
; ///< private VBI data structure
196 tt_stream_props tsp
; ///< data for VBI initialization
198 tv_param_t
* tv_param
; ///< TV parameters
204 country table entry structure (for loading freq table stored in kstvtuner.ax
207 structure have to be 2-byte aligned and have 10-byte length!!
209 typedef struct __attribute__((__packed__
)) {
210 WORD CountryCode
; ///< Country code
211 WORD CableFreqTable
; ///< index of resource with frequencies for cable channels
212 WORD BroadcastFreqTable
; ///< index of resource with frequencies for broadcast channels
213 DWORD VideoStandard
; ///< used video standard
216 information about image formats
219 uint32_t fmt
; ///< FourCC
220 const GUID
*subtype
; ///< DirectShow's subtype
221 int nBits
; ///< number of bits
222 int nCompression
; ///< complression
223 int tail
; ///< number of additional bytes followed VIDEOINFOHEADER structure
227 *---------------------------------------------------------------------------------------
229 * Methods forward declaration
231 *---------------------------------------------------------------------------------------
233 static HRESULT
init_ringbuffer(grabber_ringbuffer_t
* rb
, int buffersize
,
235 static HRESULT
show_filter_info(IBaseFilter
* pFilter
);
237 //defined in current MinGW release
238 HRESULT STDCALL
GetRunningObjectTable(DWORD
, IRunningObjectTable
**);
239 HRESULT STDCALL
CreateItemMoniker(LPCOLESTR
, LPCOLESTR
, IMoniker
**);
241 static CSampleGrabberCB
*CSampleGrabberCB_Create(grabber_ringbuffer_t
*
243 static int set_crossbar_input(priv_t
* priv
, int input
);
244 static int subtype2imgfmt(const GUID
* subtype
);
247 *---------------------------------------------------------------------------------------
249 * Global constants and variables
251 *---------------------------------------------------------------------------------------
254 lookup tables for physical connector types
256 static const struct {
259 } tv_physcon_types
[]={
260 {PhysConn_Video_Tuner
, "Tuner" },
261 {PhysConn_Video_Composite
, "Composite" },
262 {PhysConn_Video_SVideo
, "S-Video" },
263 {PhysConn_Video_RGB
, "RGB" },
264 {PhysConn_Video_YRYBY
, "YRYBY" },
265 {PhysConn_Video_SerialDigital
, "SerialDigital" },
266 {PhysConn_Video_ParallelDigital
, "ParallelDigital"},
267 {PhysConn_Video_VideoDecoder
, "VideoDecoder" },
268 {PhysConn_Video_VideoEncoder
, "VideoEncoder" },
269 {PhysConn_Video_SCART
, "SCART" },
270 {PhysConn_Video_Black
, "Blaack" },
271 {PhysConn_Audio_Tuner
, "Tuner" },
272 {PhysConn_Audio_Line
, "Line" },
273 {PhysConn_Audio_Mic
, "Mic" },
274 {PhysConn_Audio_AESDigital
, "AESDiital" },
275 {PhysConn_Audio_SPDIFDigital
, "SPDIFDigital" },
276 {PhysConn_Audio_AudioDecoder
, "AudioDecoder" },
277 {PhysConn_Audio_SCSI
, "SCSI" },
278 {PhysConn_Video_SCSI
, "SCSI" },
279 {PhysConn_Audio_AUX
, "AUX" },
280 {PhysConn_Video_AUX
, "AUX" },
281 {PhysConn_Audio_1394
, "1394" },
282 {PhysConn_Video_1394
, "1394" },
283 {PhysConn_Audio_USB
, "USB" },
284 {PhysConn_Video_USB
, "USB" },
288 static const struct {
291 } tv_chanlist2country
[]={
303 //directshow table uses eastern europe freq table for russia
305 //directshow table uses western europe freq table for germany
316 array, contains information about various supported (i hope) image formats
318 static const img_fmt img_fmt_list
[] = {
319 {IMGFMT_YUY2
, &MEDIASUBTYPE_YUY2
, 16, IMGFMT_YUY2
, 0},
320 {IMGFMT_YV12
, &MEDIASUBTYPE_YV12
, 12, IMGFMT_YV12
, 0},
321 {IMGFMT_IYUV
, &MEDIASUBTYPE_IYUV
, 12, IMGFMT_IYUV
, 0},
322 {IMGFMT_I420
, &MEDIASUBTYPE_I420
, 12, IMGFMT_I420
, 0},
323 {IMGFMT_UYVY
, &MEDIASUBTYPE_UYVY
, 16, IMGFMT_UYVY
, 0},
324 {IMGFMT_YVYU
, &MEDIASUBTYPE_YVYU
, 16, IMGFMT_YVYU
, 0},
325 {IMGFMT_YVU9
, &MEDIASUBTYPE_YVU9
, 9, IMGFMT_YVU9
, 0},
326 {IMGFMT_BGR32
, &MEDIASUBTYPE_RGB32
, 32, 0, 0},
327 {IMGFMT_BGR24
, &MEDIASUBTYPE_RGB24
, 24, 0, 0},
328 {IMGFMT_BGR16
, &MEDIASUBTYPE_RGB565
, 16, 3, 12},
329 {IMGFMT_BGR15
, &MEDIASUBTYPE_RGB555
, 16, 3, 12},
330 {0, &GUID_NULL
, 0, 0, 0}
333 #define TV_NORMS_COUNT 19
334 static const struct {
337 } tv_norms
[TV_NORMS_COUNT
] = {
339 AnalogVideo_NTSC_M
, "ntsc-m"}, {
340 AnalogVideo_NTSC_M_J
, "ntsc-mj"}, {
341 AnalogVideo_NTSC_433
, "ntsc-433"}, {
342 AnalogVideo_PAL_B
, "pal-b"}, {
343 AnalogVideo_PAL_D
, "pal-d"}, {
344 AnalogVideo_PAL_G
, "pal-g"}, {
345 AnalogVideo_PAL_H
, "pal-h"}, {
346 AnalogVideo_PAL_I
, "pal-i"}, {
347 AnalogVideo_PAL_M
, "pal-m"}, {
348 AnalogVideo_PAL_N
, "pal-n"}, {
349 AnalogVideo_PAL_60
, "pal-60"}, {
350 AnalogVideo_SECAM_B
, "secam-b"}, {
351 AnalogVideo_SECAM_D
, "secam-d"}, {
352 AnalogVideo_SECAM_G
, "secam-g"}, {
353 AnalogVideo_SECAM_H
, "secam-h"}, {
354 AnalogVideo_SECAM_K
, "secam-k"}, {
355 AnalogVideo_SECAM_K1
, "secam-k1"}, {
356 AnalogVideo_SECAM_L
, "secam-l"}, {
357 AnalogVideo_SECAM_L1
, "secam-l1"}
359 static long tv_available_norms
[TV_NORMS_COUNT
];
360 static int tv_available_norms_count
= 0;
363 static long *tv_available_inputs
;
364 static int tv_available_inputs_count
= 0;
367 *---------------------------------------------------------------------------------------
369 * Various GUID definitions
371 *---------------------------------------------------------------------------------------
373 /// CLSID definitions (used for CoCreateInstance call)
374 DEFINE_GUID(CLSID_SampleGrabber
, 0xC1F400A0, 0x3F08, 0x11d3, 0x9F, 0x0B,
375 0x00, 0x60, 0x08, 0x03, 0x9E, 0x37);
376 DEFINE_GUID(CLSID_NullRenderer
, 0xC1F400A4, 0x3F08, 0x11d3, 0x9F, 0x0B,
377 0x00, 0x60, 0x08, 0x03, 0x9E, 0x37);
378 DEFINE_GUID(CLSID_SystemDeviceEnum
, 0x62BE5D10, 0x60EB, 0x11d0, 0xBD, 0x3B,
379 0x00, 0xA0, 0xC9, 0x11, 0xCE, 0x86);
380 DEFINE_GUID(CLSID_CaptureGraphBuilder2
, 0xBF87B6E1, 0x8C27, 0x11d0, 0xB3,
381 0xF0, 0x00, 0xAA, 0x00, 0x37, 0x61, 0xC5);
382 DEFINE_GUID(CLSID_VideoInputDeviceCategory
, 0x860BB310, 0x5D01, 0x11d0,
383 0xBD, 0x3B, 0x00, 0xA0, 0xC9, 0x11, 0xCE, 0x86);
384 DEFINE_GUID(CLSID_AudioInputDeviceCategory
, 0x33d9a762, 0x90c8, 0x11d0,
385 0xbd, 0x43, 0x00, 0xa0, 0xc9, 0x11, 0xce, 0x86);
386 DEFINE_GUID(CLSID_FilterGraph
, 0xe436ebb3, 0x524f, 0x11ce, 0x9f, 0x53,
387 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70);
388 DEFINE_GUID(CLSID_SystemClock
, 0xe436ebb1, 0x524f, 0x11ce, 0x9f, 0x53,
389 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70);
391 DEFINE_GUID(CLSID_CaptureGraphBuilder
, 0xBF87B6E0, 0x8C27, 0x11d0, 0xB3,
392 0xF0, 0x00, 0xAA, 0x00, 0x37, 0x61, 0xC5);
393 DEFINE_GUID(CLSID_VideoPortManager
, 0x6f26a6cd, 0x967b, 0x47fd, 0x87, 0x4a,
394 0x7a, 0xed, 0x2c, 0x9d, 0x25, 0xa2);
395 DEFINE_GUID(IID_IPin
, 0x56a86891, 0x0ad4, 0x11ce, 0xb0, 0x3a, 0x00, 0x20,
396 0xaf, 0x0b, 0xa7, 0x70);
397 DEFINE_GUID(IID_ICaptureGraphBuilder
, 0xbf87b6e0, 0x8c27, 0x11d0, 0xb3,
398 0xf0, 0x00, 0xaa, 0x00, 0x37, 0x61, 0xc5);
399 DEFINE_GUID(IID_IFilterGraph
, 0x56a8689f, 0x0ad4, 0x11ce, 0xb0, 0x3a, 0x00,
400 0x20, 0xaf, 0x0b, 0xa7, 0x70);
401 DEFINE_GUID(PIN_CATEGORY_PREVIEW
, 0xfb6c4282, 0x0353, 0x11d1, 0x90, 0x5f,
402 0x00, 0x00, 0xc0, 0xcc, 0x16, 0xba);
405 /// IID definitions (used for QueryInterface call)
406 DEFINE_GUID(IID_IReferenceClock
, 0x56a86897, 0x0ad4, 0x11ce, 0xb0, 0x3a,
407 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70);
408 DEFINE_GUID(IID_IAMBufferNegotiation
, 0x56ED71A0, 0xAF5F, 0x11D0, 0xB3, 0xF0,
409 0x00, 0xAA, 0x00, 0x37, 0x61, 0xC5);
410 DEFINE_GUID(IID_IKsPropertySet
, 0x31efac30, 0x515c, 0x11d0, 0xa9, 0xaa,
411 0x00, 0xaa, 0x00, 0x61, 0xbe, 0x93);
412 DEFINE_GUID(IID_ISampleGrabber
, 0x6B652FFF, 0x11FE, 0x4fce, 0x92, 0xAD,
413 0x02, 0x66, 0xB5, 0xD7, 0xC7, 0x8F);
414 DEFINE_GUID(IID_ISampleGrabberCB
, 0x0579154A, 0x2B53, 0x4994, 0xB0, 0xD0,
415 0xE7, 0x73, 0x14, 0x8E, 0xFF, 0x85);
416 DEFINE_GUID(IID_ICaptureGraphBuilder2
, 0x93e5a4e0, 0x2d50, 0x11d2, 0xab,
417 0xfa, 0x00, 0xa0, 0xc9, 0xc6, 0xe3, 0x8d);
418 DEFINE_GUID(IID_ICreateDevEnum
, 0x29840822, 0x5b84, 0x11d0, 0xbd, 0x3b,
419 0x00, 0xa0, 0xc9, 0x11, 0xce, 0x86);
420 DEFINE_GUID(IID_IGraphBuilder
, 0x56a868a9, 0x0ad4, 0x11ce, 0xb0, 0x3a,
421 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70);
422 DEFINE_GUID(IID_IAMVideoProcAmp
, 0xC6E13360, 0x30AC, 0x11d0, 0xA1, 0x8C,
423 0x00, 0xA0, 0xC9, 0x11, 0x89, 0x56);
424 DEFINE_GUID(IID_IVideoWindow
, 0x56a868b4, 0x0ad4, 0x11ce, 0xb0, 0x3a, 0x00,
425 0x20, 0xaf, 0x0b, 0xa7, 0x70);
426 DEFINE_GUID(IID_IMediaControl
, 0x56a868b1, 0x0ad4, 0x11ce, 0xb0, 0x3a,
427 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70);
428 DEFINE_GUID(IID_IAMTVTuner
, 0x211A8766, 0x03AC, 0x11d1, 0x8D, 0x13, 0x00,
429 0xAA, 0x00, 0xBD, 0x83, 0x39);
430 DEFINE_GUID(IID_IAMCrossbar
, 0xc6e13380, 0x30ac, 0x11d0, 0xa1, 0x8c, 0x00,
431 0xa0, 0xc9, 0x11, 0x89, 0x56);
432 DEFINE_GUID(IID_IAMStreamConfig
, 0xc6e13340, 0x30ac, 0x11d0, 0xa1, 0x8c,
433 0x00, 0xa0, 0xc9, 0x11, 0x89, 0x56);
434 DEFINE_GUID(IID_IAMAudioInputMixer
, 0x54C39221, 0x8380, 0x11d0, 0xB3, 0xF0,
435 0x00, 0xAA, 0x00, 0x37, 0x61, 0xC5);
436 DEFINE_GUID(IID_IAMTVAudio
, 0x83EC1C30, 0x23D1, 0x11d1, 0x99, 0xE6, 0x00,
437 0xA0, 0xC9, 0x56, 0x02, 0x66);
438 DEFINE_GUID(IID_IAMAnalogVideoDecoder
, 0xC6E13350, 0x30AC, 0x11d0, 0xA1,
439 0x8C, 0x00, 0xA0, 0xC9, 0x11, 0x89, 0x56);
440 DEFINE_GUID(IID_IPropertyBag
, 0x55272a00, 0x42cb, 0x11ce, 0x81, 0x35, 0x00,
441 0xaa, 0x00, 0x4b, 0xb8, 0x51);
442 DEFINE_GUID(PIN_CATEGORY_CAPTURE
, 0xfb6c4281, 0x0353, 0x11d1, 0x90, 0x5f,
443 0x00, 0x00, 0xc0, 0xcc, 0x16, 0xba);
444 DEFINE_GUID(PIN_CATEGORY_VIDEOPORT
, 0xfb6c4285, 0x0353, 0x11d1, 0x90, 0x5f,
445 0x00, 0x00, 0xc0, 0xcc, 0x16, 0xba);
446 DEFINE_GUID(PIN_CATEGORY_PREVIEW
, 0xfb6c4282, 0x0353, 0x11d1, 0x90, 0x5f,
447 0x00, 0x00, 0xc0, 0xcc, 0x16, 0xba);
448 DEFINE_GUID(PIN_CATEGORY_VBI
, 0xfb6c4284, 0x0353, 0x11d1, 0x90, 0x5f,
449 0x00, 0x00, 0xc0, 0xcc, 0x16, 0xba);
450 DEFINE_GUID(PROPSETID_TUNER
, 0x6a2e0605, 0x28e4, 0x11d0, 0xa1, 0x8c, 0x00,
451 0xa0, 0xc9, 0x11, 0x89, 0x56);
452 DEFINE_GUID(MEDIATYPE_VBI
, 0xf72a76e1, 0xeb0a, 0x11d0, 0xac, 0xe4, 0x00,
453 0x00, 0xc0, 0xcc, 0x16, 0xba);
455 #define INSTANCEDATA_OF_PROPERTY_PTR(x) (((KSPROPERTY*)(x)) + 1)
456 #define INSTANCEDATA_OF_PROPERTY_SIZE(x) (sizeof((x)) - sizeof(KSPROPERTY))
458 #define DEVICE_NAME_MAX_LEN 2000
460 /*---------------------------------------------------------------------------------------
461 * Methods, called only from this file
462 *---------------------------------------------------------------------------------------*/
464 void set_buffer_preference(int nDiv
,WAVEFORMATEX
* pWF
,IPin
* pOutPin
,IPin
* pInPin
){
465 ALLOCATOR_PROPERTIES prop
;
466 IAMBufferNegotiation
* pBN
;
470 prop
.cbBuffer
= pWF
->nAvgBytesPerSec
/nDiv
;
473 prop
.cbBuffer
+= pWF
->nBlockAlign
- 1;
474 prop
.cbBuffer
-= prop
.cbBuffer
% pWF
->nBlockAlign
;
478 hr
=OLE_QUERYINTERFACE(pOutPin
,IID_IAMBufferNegotiation
,pBN
);
480 mp_msg(MSGT_TV
,MSGL_DBG2
,"tvi_dshow: pOutPin->QueryInterface(IID_IAMBufferNegotiation) Error: 0x%x\n",(unsigned int)hr
);
482 hr
=OLE_CALL_ARGS(pBN
,SuggestAllocatorProperties
,&prop
);
484 mp_msg(MSGT_TV
,MSGL_DBG2
,"tvi_dshow:pOutPin->SuggestAllocatorProperties Error:0x%x\n",(unsigned int)hr
);
485 OLE_RELEASE_SAFE(pBN
);
487 hr
=OLE_QUERYINTERFACE(pInPin
,IID_IAMBufferNegotiation
,pBN
);
489 mp_msg(MSGT_TV
,MSGL_DBG2
,"tvi_dshow: pInPin->QueryInterface(IID_IAMBufferNegotiation) Error: 0x%x",(unsigned int)hr
);
491 hr
=OLE_CALL_ARGS(pBN
,SuggestAllocatorProperties
,&prop
);
493 mp_msg(MSGT_TV
,MSGL_DBG2
,"tvi_dshow: pInPit->SuggestAllocatorProperties Error:0x%x\n",(unsigned int)hr
);
494 OLE_RELEASE_SAFE(pBN
);
498 *---------------------------------------------------------------------------------------
500 * CSampleGrabberCD class. Used for receiving samples from DirectShow.
502 *---------------------------------------------------------------------------------------
504 /// CSampleGrabberCD destructor
505 static void CSampleGrabberCB_Destroy(CSampleGrabberCB
* This
)
511 /// CSampleGrabberCD IUnknown interface methods implementation
512 static long STDCALL
CSampleGrabberCB_QueryInterface(ISampleGrabberCB
*
517 CSampleGrabberCB
*me
= (CSampleGrabberCB
*) This
;
520 Debug
printf("CSampleGrabberCB_QueryInterface(%p) called\n", This
);
523 for (r
= me
->interfaces
;
524 i
< sizeof(me
->interfaces
) / sizeof(me
->interfaces
[0]); r
++, i
++)
525 if (!memcmp(r
, riid
, sizeof(*r
))) {
526 OLE_CALL(This
, AddRef
);
530 Debug
printf("Query failed! (GUID: 0x%x)\n", *(unsigned int *) riid
);
531 return E_NOINTERFACE
;
534 static long STDCALL
CSampleGrabberCB_AddRef(ISampleGrabberCB
* This
)
536 CSampleGrabberCB
*me
= (CSampleGrabberCB
*) This
;
537 Debug
printf("CSampleGrabberCB_AddRef(%p) called (ref:%d)\n", This
,
539 return ++(me
->refcount
);
542 static long STDCALL
CSampleGrabberCB_Release(ISampleGrabberCB
* This
)
544 CSampleGrabberCB
*me
= (CSampleGrabberCB
*) This
;
545 Debug
printf("CSampleGrabberCB_Release(%p) called (new ref:%d)\n",
546 This
, me
->refcount
- 1);
547 if (--(me
->refcount
) == 0)
548 CSampleGrabberCB_Destroy(me
);
553 HRESULT STDCALL
CSampleGrabberCB_BufferCB(ISampleGrabberCB
* This
,
555 BYTE
* pBuffer
, long lBufferLen
)
557 CSampleGrabberCB
*this = (CSampleGrabberCB
*) This
;
558 grabber_ringbuffer_t
*rb
= this->pbuf
;
563 if (!rb
->ringbuffer
) {
564 rb
->buffersize
/= lBufferLen
;
565 if (init_ringbuffer(rb
, rb
->buffersize
, lBufferLen
) != S_OK
)
568 mp_msg(MSGT_TV
, MSGL_DBG4
,
569 "tvi_dshow: BufferCB(%p): len=%ld ts=%f\n", This
, lBufferLen
, SampleTime
);
570 EnterCriticalSection(rb
->pMutex
);
571 if (rb
->count
>= rb
->buffersize
) {
572 rb
->head
= (rb
->head
+ 1) % rb
->buffersize
;
576 memcpy(rb
->ringbuffer
[rb
->tail
], pBuffer
,
577 lBufferLen
< rb
->blocksize
? lBufferLen
: rb
->blocksize
);
578 rb
->dpts
[rb
->tail
] = SampleTime
;
579 rb
->tail
= (rb
->tail
+ 1) % rb
->buffersize
;
581 LeaveCriticalSection(rb
->pMutex
);
586 /// wrapper. directshow does the same when BufferCB callback is requested
587 HRESULT STDCALL
CSampleGrabberCB_SampleCB(ISampleGrabberCB
* This
,
589 LPMEDIASAMPLE pSample
)
593 long long tStart
,tEnd
;
595 grabber_ringbuffer_t
*rb
= ((CSampleGrabberCB
*)This
)->pbuf
;
597 len
=OLE_CALL(pSample
,GetSize
);
599 hr
=OLE_CALL_ARGS(pSample
,GetTime
,&tStart
,&tEnd
);
603 mp_msg(MSGT_TV
, MSGL_DBG4
,"tvi_dshow: SampleCB(%p): %d/%d %f\n", This
,rb
->count
,rb
->buffersize
,1e-7*tStart
);
604 hr
=OLE_CALL_ARGS(pSample
,GetPointer
,(void*)&buf
);
608 hr
=CSampleGrabberCB_BufferCB(This
,1e-7*tStart
,buf
,len
);
613 /// main grabbing routine
614 static CSampleGrabberCB
*CSampleGrabberCB_Create(grabber_ringbuffer_t
*
617 CSampleGrabberCB
*This
= malloc(sizeof(CSampleGrabberCB
));
621 This
->lpVtbl
= malloc(sizeof(ISampleGrabberVtbl
));
623 CSampleGrabberCB_Destroy(This
);
627 This
->lpVtbl
->QueryInterface
= CSampleGrabberCB_QueryInterface
;
628 This
->lpVtbl
->AddRef
= CSampleGrabberCB_AddRef
;
629 This
->lpVtbl
->Release
= CSampleGrabberCB_Release
;
630 This
->lpVtbl
->SampleCB
= CSampleGrabberCB_SampleCB
;
631 This
->lpVtbl
->BufferCB
= CSampleGrabberCB_BufferCB
;
633 This
->interfaces
[0] = IID_IUnknown
;
634 This
->interfaces
[1] = IID_ISampleGrabberCB
;
642 *---------------------------------------------------------------------------------------
644 * ROT related methods (register, unregister)
646 *---------------------------------------------------------------------------------------
649 Registering graph in ROT. User will be able to connect to graph from GraphEdit.
651 static HRESULT
AddToRot(IUnknown
* pUnkGraph
, DWORD
* pdwRegister
)
654 IRunningObjectTable
*pROT
;
658 if (FAILED(GetRunningObjectTable(0, &pROT
))) {
661 wsprintfW(wsz
, L
"FilterGraph %08x pid %08x", (DWORD_PTR
) pUnkGraph
,
662 GetCurrentProcessId());
663 hr
= CreateItemMoniker(L
"!", wsz
, &pMoniker
);
665 hr
= OLE_CALL_ARGS(pROT
, Register
, ROTFLAGS_REGISTRATIONKEEPSALIVE
,
666 pUnkGraph
, pMoniker
, pdwRegister
);
667 OLE_RELEASE_SAFE(pMoniker
);
669 OLE_RELEASE_SAFE(pROT
);
673 /// Unregistering graph in ROT
674 static void RemoveFromRot(DWORD dwRegister
)
676 IRunningObjectTable
*pROT
;
677 if (SUCCEEDED(GetRunningObjectTable(0, &pROT
))) {
678 OLE_CALL_ARGS(pROT
, Revoke
, dwRegister
);
679 OLE_RELEASE_SAFE(pROT
);
684 *---------------------------------------------------------------------------------------
686 * ringbuffer related methods (init, destroy)
688 *---------------------------------------------------------------------------------------
691 * \brief ringbuffer destroying routine
693 * \param rb pointer to empty (just allocated) ringbuffer structure
695 * \note routine does not frees memory, allocated for grabber_rinbuffer_s structure
697 static void destroy_ringbuffer(grabber_ringbuffer_t
* rb
)
704 if (rb
->ringbuffer
) {
705 for (i
= 0; i
< rb
->buffersize
; i
++)
706 if (rb
->ringbuffer
[i
])
707 free(rb
->ringbuffer
[i
]);
708 free(rb
->ringbuffer
);
709 rb
->ringbuffer
= NULL
;
716 DeleteCriticalSection(rb
->pMutex
);
729 * \brief ringbuffer initialization
731 * \param rb pointer to empty (just allocated) ringbuffer structure
732 * \param buffersize size of buffer in blocks
733 * \param blocksize size of buffer's block
735 * \return S_OK if success
736 * \return E_OUTOFMEMORY not enough memory
738 * \note routine does not allocates memory for grabber_rinbuffer_s structure
740 static HRESULT
init_ringbuffer(grabber_ringbuffer_t
* rb
, int buffersize
,
746 return E_OUTOFMEMORY
;
748 rb
->buffersize
= buffersize
< 2 ? 2 : buffersize
;
749 rb
->blocksize
= blocksize
;
751 mp_msg(MSGT_TV
, MSGL_DBG2
, "tvi_dshow: Capture buffer: %d blocks of %d bytes.\n",
752 rb
->buffersize
, rb
->blocksize
);
754 rb
->ringbuffer
= (char **) malloc(rb
->buffersize
* sizeof(char *));
757 memset(rb
->ringbuffer
, 0, rb
->buffersize
* sizeof(char *));
759 for (i
= 0; i
< rb
->buffersize
; i
++) {
760 rb
->ringbuffer
[i
] = (char *) malloc(rb
->blocksize
* sizeof(char));
761 if (!rb
->ringbuffer
[i
]) {
762 destroy_ringbuffer(rb
);
763 return E_OUTOFMEMORY
;
766 rb
->dpts
= (double*) malloc(rb
->buffersize
* sizeof(double));
768 destroy_ringbuffer(rb
);
769 return E_OUTOFMEMORY
;
775 rb
->pMutex
= (CRITICAL_SECTION
*) malloc(sizeof(CRITICAL_SECTION
));
777 destroy_ringbuffer(rb
);
778 return E_OUTOFMEMORY
;
780 InitializeCriticalSection(rb
->pMutex
);
785 *---------------------------------------------------------------------------------------
787 * Tuner related methods (frequency, capabilities, etc
789 *---------------------------------------------------------------------------------------
792 * \brief returns string with name for givend PsysCon_* constant
794 * \param lPhysicalType constant from PhysicalConnectorType enumeration
796 * \return pointer to string with apropriate name
799 * Caller should not free returned pointer
801 static char *physcon2str(const long lPhysicalType
)
804 for(i
=0; tv_physcon_types
[i
].name
; i
++)
805 if(tv_physcon_types
[i
].type
==lPhysicalType
)
806 return tv_physcon_types
[i
].name
;
811 * \brief converts MPlayer's chanlist to system country code.
813 * \param chanlist MPlayer's chanlist name
815 * \return system country code
818 * After call to IAMTVTuner::put_CountryCode with returned value tuner switches to frequency table used in specified
819 * country (which is usually larger then MPlayer's one, so workaround will work fine).
822 * Resolve trouble with cable channels (DirectShow's tuners must be switched between broadcast and cable channels modes.
824 static int chanlist2country(char *chanlist
)
827 for(i
=0; tv_chanlist2country
[i
].chanlist_name
; i
++)
828 if (!strcmp(chanlist
, tv_chanlist2country
[i
].chanlist_name
))
830 return tv_chanlist2country
[i
].country_code
;
834 * \brief loads specified resource from module and return pointer to it
836 * \param hDLL valid module desriptor
837 * \param index index of resource. resource with name "#<index>" will be loaded
839 * \return pointer to loader resource or NULL if error occured
841 static void *GetRC(HMODULE hDLL
, int index
)
848 snprintf(szRCDATA
, 10, "#%d", (int)RT_RCDATA
);
849 snprintf(szName
, 10, "#%d", index
);
851 hRes
= FindResource(hDLL
, szName
, szRCDATA
);
855 hTable
= LoadResource(hDLL
, hRes
);
859 return LockResource(hTable
);
863 * \brief loads frequency table for given country from kstvtune.ax
865 * \param[in] nCountry - country code
866 * \param[in] nInputType (TunerInputCable or TunerInputAntenna)
867 * \param[out] pplFreqTable - address of variable that receives pointer to array, containing frequencies
868 * \param[out] pnLen length of array
869 * \param[out] pnFirst - channel number of first entry in array (nChannelMax)
871 * \return S_OK if success
872 * \return E_POINTER pplFreqTable==NULL || plFirst==NULL || pnLen==NULL
873 * \return E_FAIL error occured during load
876 * - array must be freed by caller
877 * - MSDN says that it is not neccessery to unlock or free resource. It will be done after unloading DLL
879 static HRESULT
load_freq_table(int nCountry
, int nInputType
,
880 long **pplFreqTable
, int *pnLen
,
885 TRCCountryList
*pCountryList
;
888 mp_msg(MSGT_TV
, MSGL_DBG4
, "tvi_dshow: load_freq_table called %d (%d)\n",nCountry
,nInputType
);
889 /* ASSERT(sizeof(TRCCountryList)==10); // need properly aligned structure */
891 if (!pplFreqTable
|| !pnFirst
|| !pnLen
)
896 hDLL
= LoadLibrary("kstvtune.ax");
900 pCountryList
= GetRC(hDLL
, 9999);
905 for (i
= 0; pCountryList
[i
].CountryCode
!= 0; i
++)
906 if (pCountryList
[i
].CountryCode
== nCountry
)
908 if (pCountryList
[i
].CountryCode
== 0) {
912 if (nInputType
== TunerInputCable
)
913 index
= pCountryList
[i
].CableFreqTable
;
915 index
= pCountryList
[i
].BroadcastFreqTable
;
917 plFreqTable
= GetRC(hDLL
, index
); //First element is number of first channel, second - number of last channel
922 *pnFirst
= plFreqTable
[0];
923 *pnLen
= (int) (plFreqTable
[1] - plFreqTable
[0] + 1);
924 *pplFreqTable
= (long *) malloc((*pnLen
) * sizeof(long));
925 if (!*pplFreqTable
) {
929 for (i
= 0; i
< *pnLen
; i
++) {
930 (*pplFreqTable
)[i
] = plFreqTable
[i
+ 2];
937 * \brief tunes to given frequency through IKsPropertySet call
939 * \param pTVTuner IAMTVTuner interface of capture device
940 * \param lFreq frequency to tune (in Hz)
942 * \return S_OK success
943 * \return apropriate error code otherwise
946 * Due to either bug in driver or error in following code calll to IKsProperty::Set
947 * in this methods always fail with error 0x8007007a.
949 * \todo test code on other machines and an error
951 static HRESULT
set_frequency_direct(IAMTVTuner
* pTVTuner
, long lFreq
)
954 DWORD dwSupported
= 0;
956 KSPROPERTY_TUNER_MODE_CAPS_S mode_caps
;
957 KSPROPERTY_TUNER_FREQUENCY_S frequency
;
958 IKsPropertySet
*pKSProp
;
960 mp_msg(MSGT_TV
, MSGL_DBG4
, "tvi_dshow: set_frequency_direct called\n");
962 memset(&mode_caps
, 0, sizeof(mode_caps
));
963 memset(&frequency
, 0, sizeof(frequency
));
965 hr
= OLE_QUERYINTERFACE(pTVTuner
, IID_IKsPropertySet
, pKSProp
);
967 return hr
; //no IKsPropertySet interface
969 mode_caps
.Mode
= AMTUNER_MODE_TV
;
970 hr
= OLE_CALL_ARGS(pKSProp
, QuerySupported
, &PROPSETID_TUNER
,
971 KSPROPERTY_TUNER_MODE_CAPS
, &dwSupported
);
973 OLE_RELEASE_SAFE(pKSProp
);
977 if (!dwSupported
& KSPROPERTY_SUPPORT_GET
) {
978 OLE_RELEASE_SAFE(pKSProp
);
979 return E_FAIL
; //PROPSETID_TINER not supported
982 hr
= OLE_CALL_ARGS(pKSProp
, Get
, &PROPSETID_TUNER
,
983 KSPROPERTY_TUNER_MODE_CAPS
,
984 INSTANCEDATA_OF_PROPERTY_PTR(&mode_caps
),
985 INSTANCEDATA_OF_PROPERTY_SIZE(mode_caps
),
986 &mode_caps
, sizeof(mode_caps
), &cbBytes
);
988 frequency
.Frequency
= lFreq
;
990 if (mode_caps
.Strategy
== KS_TUNER_STRATEGY_DRIVER_TUNES
)
991 frequency
.TuningFlags
= KS_TUNER_TUNING_FINE
;
993 frequency
.TuningFlags
= KS_TUNER_TUNING_EXACT
;
995 if (lFreq
< mode_caps
.MinFrequency
|| lFreq
> mode_caps
.MaxFrequency
) {
996 OLE_RELEASE_SAFE(pKSProp
);
1000 hr
= OLE_CALL_ARGS(pKSProp
, Set
, &PROPSETID_TUNER
,
1001 KSPROPERTY_TUNER_FREQUENCY
,
1002 INSTANCEDATA_OF_PROPERTY_PTR(&frequency
),
1003 INSTANCEDATA_OF_PROPERTY_SIZE(frequency
),
1004 &frequency
, sizeof(frequency
));
1006 OLE_RELEASE_SAFE(pKSProp
);
1010 OLE_RELEASE_SAFE(pKSProp
);
1016 * \brief find channel with nearest frequency and set it
1018 * \param priv driver's private data
1019 * \param lFreq frequency in Hz
1021 * \return S_OK if success
1022 * \return E_FAIL if error occured
1024 static HRESULT
set_nearest_freq(priv_t
* priv
, long lFreq
)
1030 TunerInputType tunerInput
;
1033 mp_msg(MSGT_TV
, MSGL_DBG4
, "tvi_dshow: set_nearest_freq called\n");
1034 if(priv
->freq_table_len
== -1 && !priv
->freq_table
) {
1036 hr
= OLE_CALL_ARGS(priv
->pTVTuner
, get_ConnectInput
, &lInput
);
1037 if(FAILED(hr
)){ //Falling back to 0
1041 hr
= OLE_CALL_ARGS(priv
->pTVTuner
, get_InputType
, lInput
, &tunerInput
);
1043 if (load_freq_table(chanlist2country(priv
->tv_param
->chanlist
), tunerInput
, &(priv
->freq_table
), &(priv
->freq_table_len
), &(priv
->first_channel
)) != S_OK
) {//FIXME
1044 priv
->freq_table_len
=0;
1045 priv
->freq_table
=NULL
;
1046 mp_msg(MSGT_TV
, MSGL_ERR
, MSGTR_TVI_DS_UnableExtractFreqTable
);
1049 mp_msg(MSGT_TV
, MSGL_V
, MSGTR_TVI_DS_FreqTableLoaded
, tunerInput
== TunerInputAntenna
? "broadcast" : "cable",
1050 chanlist2country(priv
->tv_param
->chanlist
), priv
->freq_table_len
);
1053 if (priv
->freq_table_len
<= 0)
1056 //FIXME: rewrite search algo
1058 for (i
= 0; i
< priv
->freq_table_len
; i
++) {
1059 if (nChannel
== -1 || labs(lFreq
- priv
->freq_table
[i
]) < lFreqDiff
) {
1060 nChannel
= priv
->first_channel
+ i
;
1061 lFreqDiff
= labs(lFreq
- priv
->freq_table
[i
]);
1064 if (nChannel
== -1) {
1065 mp_msg(MSGT_TV
,MSGL_ERR
, MSGTR_TVI_DS_UnableFindNearestChannel
);
1068 hr
= OLE_CALL_ARGS(priv
->pTVTuner
, put_Channel
, nChannel
,
1069 AMTUNER_SUBCHAN_DEFAULT
, AMTUNER_SUBCHAN_DEFAULT
);
1071 mp_msg(MSGT_TV
,MSGL_ERR
,MSGTR_TVI_DS_UnableToSetChannel
, (unsigned int)hr
);
1078 * \brief setting frequency. decides whether use direct call/workaround
1080 * \param priv driver's private data
1081 * \param lFreq frequency in Hz
1083 * \return TVI_CONTROL_TRUE if success
1084 * \return TVI_CONTROL_FALSE if error occured
1086 * \todo check for freq boundary
1088 static int set_frequency(priv_t
* priv
, long lFreq
)
1092 mp_msg(MSGT_TV
, MSGL_DBG4
, "tvi_dshow: set_frequency called\n");
1093 if (!priv
->pTVTuner
)
1094 return TVI_CONTROL_FALSE
;
1095 if (priv
->direct_setfreq_call
) { //using direct call to set frequency
1096 hr
= set_frequency_direct(priv
->pTVTuner
, lFreq
);
1098 mp_msg(MSGT_TV
, MSGL_V
, MSGTR_TVI_DS_DirectSetFreqFailed
);
1099 priv
->direct_setfreq_call
= 0;
1102 if (!priv
->direct_setfreq_call
) {
1103 hr
= set_nearest_freq(priv
, lFreq
);
1106 return TVI_CONTROL_FALSE
;
1108 priv
->pGrabber
->ClearBuffer(priv
->pGrabber
);
1110 return TVI_CONTROL_TRUE
;
1114 * \brief return current frequency from tuner (in Hz)
1116 * \param pTVTuner IAMTVTuner interface of tuner
1117 * \param plFreq address of variable that receives current frequency
1119 * \return S_OK success
1120 * \return E_POINTER pTVTuner==NULL || plFreq==NULL
1121 * \return apropriate error code otherwise
1123 static HRESULT
get_frequency_direct(IAMTVTuner
* pTVTuner
, long *plFreq
)
1126 KSPROPERTY_TUNER_STATUS_S TunerStatus
;
1128 IKsPropertySet
*pKSProp
;
1129 mp_msg(MSGT_TV
, MSGL_DBG4
, "tvi_dshow: get_frequency_direct called\n");
1134 hr
= OLE_QUERYINTERFACE(pTVTuner
, IID_IKsPropertySet
, pKSProp
);
1136 mp_msg(MSGT_TV
, MSGL_DBG2
, "tvi_dshow: Get freq QueryInterface failed\n");
1140 hr
= OLE_CALL_ARGS(pKSProp
, Get
, &PROPSETID_TUNER
,
1141 KSPROPERTY_TUNER_STATUS
,
1142 INSTANCEDATA_OF_PROPERTY_PTR(&TunerStatus
),
1143 INSTANCEDATA_OF_PROPERTY_SIZE(TunerStatus
),
1144 &TunerStatus
, sizeof(TunerStatus
), &cbBytes
);
1146 mp_msg(MSGT_TV
, MSGL_DBG2
, "tvi_dshow: Get freq Get failure\n");
1149 *plFreq
= TunerStatus
.CurrentFrequency
;
1154 * \brief gets current frequency
1156 * \param priv driver's private data structure
1157 * \param plFreq - pointer to long int to store frequency to (in Hz)
1159 * \return TVI_CONTROL_TRUE if success, TVI_CONTROL_FALSE otherwise
1161 static int get_frequency(priv_t
* priv
, long *plFreq
)
1165 mp_msg(MSGT_TV
, MSGL_DBG4
, "tvi_dshow: get_frequency called\n");
1167 if (!plFreq
|| !priv
->pTVTuner
)
1168 return TVI_CONTROL_FALSE
;
1170 if (priv
->direct_getfreq_call
) { //using direct call to get frequency
1171 hr
= get_frequency_direct(priv
->pTVTuner
, plFreq
);
1173 mp_msg(MSGT_TV
, MSGL_INFO
, MSGTR_TVI_DS_DirectGetFreqFailed
);
1174 priv
->direct_getfreq_call
= 0;
1177 if (!priv
->direct_getfreq_call
) {
1178 hr
=OLE_CALL_ARGS(priv
->pTVTuner
, get_VideoFrequency
, plFreq
);
1180 return TVI_CONTROL_FALSE
;
1183 return TVI_CONTROL_TRUE
;
1187 * \brief get tuner capabilities
1189 * \param priv driver's private data
1191 static void get_capabilities(priv_t
* priv
)
1193 long lAvailableFormats
;
1196 long lInputPins
, lOutputPins
, lRelated
, lPhysicalType
;
1200 PIN_DIRECTION ThisPinDir
;
1202 IAMAudioInputMixer
*pIAMixer
;
1204 mp_msg(MSGT_TV
, MSGL_DBG4
, "tvi_dshow: get_capabilities called\n");
1205 if (priv
->pTVTuner
) {
1207 mp_msg(MSGT_TV
, MSGL_V
, MSGTR_TVI_DS_SupportedNorms
);
1208 hr
= OLE_CALL_ARGS(priv
->pTVTuner
, get_AvailableTVFormats
,
1209 &lAvailableFormats
);
1211 tv_available_norms_count
= 0;
1213 for (i
= 0; i
< TV_NORMS_COUNT
; i
++) {
1214 if (lAvailableFormats
& tv_norms
[i
].index
) {
1215 tv_available_norms
[tv_available_norms_count
] = i
;
1216 mp_msg(MSGT_TV
, MSGL_V
, " %d=%s;",
1217 tv_available_norms_count
+ 1, tv_norms
[i
].name
);
1218 tv_available_norms_count
++;
1222 mp_msg(MSGT_TV
, MSGL_INFO
, "\n");
1224 if (priv
->pCrossbar
) {
1225 OLE_CALL_ARGS(priv
->pCrossbar
, get_PinCounts
, &lOutputPins
,
1228 tv_available_inputs
= (long *) malloc(sizeof(long) * lInputPins
);
1229 tv_available_inputs_count
= 0;
1231 mp_msg(MSGT_TV
, MSGL_V
, MSGTR_TVI_DS_AvailableVideoInputs
);
1232 for (i
= 0; i
< lInputPins
; i
++) {
1233 OLE_CALL_ARGS(priv
->pCrossbar
, get_CrossbarPinInfo
, 1, i
,
1234 &lRelated
, &lPhysicalType
);
1236 if (lPhysicalType
< 0x1000) {
1237 tv_available_inputs
[tv_available_inputs_count
++] = i
;
1238 mp_msg(MSGT_TV
, MSGL_V
, " %d=%s;",
1239 tv_available_inputs_count
- 1,
1240 physcon2str(lPhysicalType
));
1243 mp_msg(MSGT_TV
, MSGL_INFO
, "\n");
1245 set_crossbar_input(priv
, 0);
1248 if (priv
->adev_index
!= -1) {
1249 hr
= OLE_CALL_ARGS(priv
->chains
[1]->pCaptureFilter
, EnumPins
, &pEnum
);
1252 mp_msg(MSGT_TV
, MSGL_V
, MSGTR_TVI_DS_AvailableAudioInputs
);
1254 while (OLE_CALL_ARGS(pEnum
, Next
, 1, &pPin
, NULL
) == S_OK
) {
1255 memset(&pi
, 0, sizeof(pi
));
1256 memset(tmp
, 0, 200);
1257 OLE_CALL_ARGS(pPin
, QueryDirection
, &ThisPinDir
);
1258 if (ThisPinDir
== PINDIR_INPUT
) {
1259 OLE_CALL_ARGS(pPin
, QueryPinInfo
, &pi
);
1260 wtoa(pi
.achName
, tmp
, 200);
1261 OLE_RELEASE_SAFE(pi
.pFilter
);
1262 mp_msg(MSGT_TV
, MSGL_V
, " %d=%s", i
, tmp
);
1263 mp_msg(MSGT_TV
, MSGL_DBG3
, " (%p)", pPin
);
1264 hr
= OLE_QUERYINTERFACE(pPin
, IID_IAMAudioInputMixer
,pIAMixer
);
1265 if (SUCCEEDED(hr
)) {
1266 if (i
== priv
->tv_param
->audio_id
) {
1267 OLE_CALL_ARGS(pIAMixer
, put_Enable
, TRUE
);
1268 if(priv
->tv_param
->volume
>0)
1269 OLE_CALL_ARGS(pIAMixer
, put_MixLevel
, 0.01 * priv
->tv_param
->volume
);
1272 OLE_CALL_ARGS(pIAMixer
, put_MixLevel
, 1.0);
1274 mp_msg(MSGT_TV
, MSGL_V
, MSGTR_TVI_DS_InputSelected
);
1276 OLE_CALL_ARGS(pIAMixer
, put_Enable
, FALSE
);
1278 OLE_CALL_ARGS(pIAMixer
, put_MixLevel
, 0.0);
1281 OLE_RELEASE_SAFE(pIAMixer
);
1283 mp_msg(MSGT_TV
, MSGL_V
, ";");
1284 OLE_RELEASE_SAFE(pPin
);
1288 mp_msg(MSGT_TV
, MSGL_INFO
, "\n");
1289 OLE_RELEASE_SAFE(pEnum
);
1294 *---------------------------------------------------------------------------------------
1296 * Filter related methods
1298 *---------------------------------------------------------------------------------------
1301 * \brief routine for reconnecting two pins with new media type
1302 * \param pGraph IGraphBuilder interface
1303 * \param chan chain data
1304 * \param pmt [in/out] new mediatype for pin connection
1306 * \return S_OK if operation successfult, error code otherwise
1307 * will also return media type of new connection into pmt variable
1309 static HRESULT
reconnect_pins(IGraphBuilder
*pGraph
, chain_t
*chain
, AM_MEDIA_TYPE
*pmt
)
1311 AM_MEDIA_TYPE old_mt
;
1315 /* save old media type for reconnection in case of error */
1316 hr
= OLE_CALL_ARGS(chain
->pCapturePin
, ConnectionMediaType
, &old_mt
);
1320 hr
= OLE_CALL(chain
->pCapturePin
, Disconnect
);
1324 hr
= OLE_CALL_ARGS(chain
->pSG
, SetMediaType
, pmt
);
1328 hr
= OLE_CALL_ARGS(pGraph
, Connect
, chain
->pCapturePin
, chain
->pSGIn
);
1331 OLE_CALL_ARGS(chain
->pSG
, SetMediaType
, &old_mt
);
1332 OLE_CALL_ARGS(pGraph
, Connect
, chain
->pCapturePin
, chain
->pSGIn
);
1335 hr
= OLE_CALL_ARGS(chain
->pCapturePin
, ConnectionMediaType
, &old_mt
);
1341 CopyMediaType(pmt
, &old_mt
);
1342 FreeMediaType(&old_mt
);
1347 * \brief building in graph audio/video capture chain
1349 * \param priv driver's private data
1350 * \param pCaptureFilter pointer to capture device's IBaseFilter interface
1351 * \param pbuf ringbuffer data structure
1352 * \param pmt media type for chain (AM_MEDIA_TYPE)
1354 * \note routine does not frees memory, allocated for grabber_rinbuffer_s structure
1356 static HRESULT
build_sub_graph(priv_t
* priv
, chain_t
* chain
, const GUID
* ppin_category
)
1359 int nFormatProbed
= 0;
1364 IBaseFilter
*pNR
= NULL
;
1368 //No supported formats
1369 if(!chain
->arpmt
[0])
1373 hr
= OLE_CALL_ARGS(priv
->pBuilder
, FindPin
,
1374 (IUnknown
*) chain
->pCaptureFilter
,
1375 PINDIR_OUTPUT
, ppin_category
,
1376 chain
->majortype
, FALSE
, 0, &chain
->pCapturePin
);
1378 mp_msg(MSGT_TV
,MSGL_DBG2
, "tvi_dshow: FindPin(pCapturePin) call failed. Error:0x%x\n", (unsigned int)hr
);
1381 /* Addinf SampleGrabber filter for video stream */
1382 hr
= CoCreateInstance((GUID
*) & CLSID_SampleGrabber
, NULL
,CLSCTX_INPROC_SERVER
, &IID_IBaseFilter
,(void *) &chain
->pSGF
);
1384 mp_msg(MSGT_TV
,MSGL_DBG2
, "tvi_dshow: CoCreateInstance(SampleGrabber) call failed. Error:0x%x\n", (unsigned int)hr
);
1387 hr
= OLE_CALL_ARGS(priv
->pGraph
, AddFilter
, chain
->pSGF
, L
"Sample Grabber");
1389 mp_msg(MSGT_TV
,MSGL_DBG2
,"tvi_dshow: AddFilter(SampleGrabber) call failed. Error:0x%x\n", (unsigned int)hr
);
1392 hr
= OLE_CALL_ARGS(priv
->pBuilder
, FindPin
, (IUnknown
*) chain
->pSGF
,PINDIR_INPUT
, NULL
, NULL
, FALSE
, 0, &chain
->pSGIn
);
1394 mp_msg(MSGT_TV
,MSGL_DBG2
,"tvi_dshow: FindPin(pSGIn) call failed. Error:0x%x\n", (unsigned int)hr
);
1397 hr
= OLE_CALL_ARGS(priv
->pBuilder
, FindPin
, (IUnknown
*) chain
->pSGF
,PINDIR_OUTPUT
, NULL
, NULL
, FALSE
, 0, &pSGOut
);
1399 mp_msg(MSGT_TV
,MSGL_DBG2
,"tvi_dshow: FindPin(pSGOut) call failed. Error:0x%x\n", (unsigned int)hr
);
1403 /* creating ringbuffer for video samples */
1404 chain
->pCSGCB
= CSampleGrabberCB_Create(chain
->rbuf
);
1406 mp_msg(MSGT_TV
,MSGL_DBG2
, "tvi_dshow: CSampleGrabberCB_Create(pbuf) call failed. Error:0x%x\n", (unsigned int)E_OUTOFMEMORY
);
1410 /* initializing SampleGrabber filter */
1411 hr
= OLE_QUERYINTERFACE(chain
->pSGF
, IID_ISampleGrabber
, chain
->pSG
);
1413 mp_msg(MSGT_TV
,MSGL_DBG2
,"tvi_dshow: QueryInterface(IID_ISampleGrabber) call failed. Error:0x%x\n", (unsigned int)hr
);
1416 // hr = OLE_CALL_ARGS(pSG, SetCallback, (ISampleGrabberCB *) pCSGCB, 1); //we want to receive copy of sample's data
1417 hr
= OLE_CALL_ARGS(chain
->pSG
, SetCallback
, (ISampleGrabberCB
*) chain
->pCSGCB
, 0); //we want to receive sample
1420 mp_msg(MSGT_TV
,MSGL_DBG2
,"tvi_dshow: SetCallback(pSG) call failed. Error:0x%x\n", (unsigned int)hr
);
1423 hr
= OLE_CALL_ARGS(chain
->pSG
, SetOneShot
, FALSE
); //... for all frames
1425 mp_msg(MSGT_TV
,MSGL_DBG2
,"tvi_dshow: SetOneShot(pSG) call failed. Error:0x%x\n", (unsigned int)hr
);
1428 hr
= OLE_CALL_ARGS(chain
->pSG
, SetBufferSamples
, FALSE
); //... do not buffer samples in sample grabber
1430 mp_msg(MSGT_TV
,MSGL_DBG2
,"tvi_dshow: SetBufferSamples(pSG) call failed. Error:0x%x\n", (unsigned int)hr
);
1434 if(priv
->tv_param
->normalize_audio_chunks
&& chain
->type
==audio
){
1435 set_buffer_preference(20,(WAVEFORMATEX
*)(chain
->arpmt
[nFormatProbed
]->pbFormat
),chain
->pCapturePin
,chain
->pSGIn
);
1438 for(nFormatProbed
=0; chain
->arpmt
[nFormatProbed
]; nFormatProbed
++)
1440 DisplayMediaType("Probing format", chain
->arpmt
[nFormatProbed
]);
1441 hr
= OLE_CALL_ARGS(chain
->pSG
, SetMediaType
, chain
->arpmt
[nFormatProbed
]); //set desired mediatype
1443 mp_msg(MSGT_TV
,MSGL_DBG2
,"tvi_dshow: SetMediaType(pSG) call failed. Error:0x%x\n", (unsigned int)hr
);
1446 /* connecting filters together: VideoCapture --> SampleGrabber */
1447 hr
= OLE_CALL_ARGS(priv
->pGraph
, Connect
, chain
->pCapturePin
, chain
->pSGIn
);
1449 mp_msg(MSGT_TV
,MSGL_DBG2
,"tvi_dshow: Unable to create pCapturePin<->pSGIn connection. Error:0x%x\n", (unsigned int)hr
);
1455 if(!chain
->arpmt
[nFormatProbed
])
1457 mp_msg(MSGT_TV
, MSGL_WARN
, "tvi_dshow: Unable to negotiate media format\n");
1462 hr
= OLE_CALL_ARGS(chain
->pCapturePin
, ConnectionMediaType
, chain
->pmt
);
1465 mp_msg(MSGT_TV
, MSGL_WARN
, MSGTR_TVI_DS_GetActualMediatypeFailed
, (unsigned int)hr
);
1468 if(priv
->tv_param
->hidden_video_renderer
){
1469 IEnumFilters
* pEnum
;
1470 IBaseFilter
* pFilter
;
1472 hr
=OLE_CALL_ARGS(priv
->pBuilder
,RenderStream
,NULL
,NULL
,(IUnknown
*)chain
->pCapturePin
,NULL
,NULL
);
1474 OLE_CALL_ARGS(priv
->pGraph
, EnumFilters
, &pEnum
);
1475 while (OLE_CALL_ARGS(pEnum
, Next
, 1, &pFilter
, NULL
) == S_OK
) {
1476 LPVIDEOWINDOW pVideoWindow
;
1477 hr
= OLE_QUERYINTERFACE(pFilter
, IID_IVideoWindow
, pVideoWindow
);
1480 OLE_CALL_ARGS(pVideoWindow
,put_Visible
,/* OAFALSE*/ 0);
1481 OLE_CALL_ARGS(pVideoWindow
,put_AutoShow
,/* OAFALSE*/ 0);
1482 OLE_RELEASE_SAFE(pVideoWindow
);
1484 OLE_RELEASE_SAFE(pFilter
);
1486 OLE_RELEASE_SAFE(pEnum
);
1491 Code below is disabled, because terminating chain with NullRenderer leads to jerky video.
1492 Perhaps, this happens because NullRenderer filter discards each received
1493 frame while discarded frames causes live source filter to dramatically reduce frame rate.
1495 /* adding sink for video stream */
1496 hr
= CoCreateInstance((GUID
*) & CLSID_NullRenderer
, NULL
,CLSCTX_INPROC_SERVER
, &IID_IBaseFilter
,(void *) &pNR
);
1498 mp_msg(MSGT_TV
,MSGL_DBG2
,"tvi_dshow: CoCreateInstance(NullRenderer) call failed. Error:0x%x\n", (unsigned int)hr
);
1501 hr
= OLE_CALL_ARGS(priv
->pGraph
, AddFilter
, pNR
, L
"Null Renderer");
1503 mp_msg(MSGT_TV
,MSGL_DBG2
,"tvi_dshow: AddFilter(NullRenderer) call failed. Error:0x%x\n", (unsigned int)hr
);
1506 hr
= OLE_CALL_ARGS(priv
->pBuilder
, FindPin
, (IUnknown
*) pNR
,PINDIR_INPUT
, NULL
, NULL
, FALSE
, 0, &pNRIn
);
1508 mp_msg(MSGT_TV
,MSGL_DBG2
,"tvi_dshow: FindPin(pNRIn) call failed. Error:0x%x\n", (unsigned int)hr
);
1512 Prevent ending VBI chain with NullRenderer filter, because this causes VBI pin disconnection
1514 if(memcmp(&(arpmt
[nFormatProbed
]->majortype
),&MEDIATYPE_VBI
,16)){
1515 /* connecting filters together: SampleGrabber --> NullRenderer */
1516 hr
= OLE_CALL_ARGS(priv
->pGraph
, Connect
, pSGOut
, pNRIn
);
1518 mp_msg(MSGT_TV
,MSGL_DBG2
,"tvi_dshow: Unable to create pSGOut<->pNRIn connection. Error:0x%x\n", (unsigned int)hr
);
1528 OLE_RELEASE_SAFE(pSGOut
);
1529 OLE_RELEASE_SAFE(pNR
);
1530 OLE_RELEASE_SAFE(pNRIn
);
1536 * \brief configures crossbar for grabbing video stream from given input
1538 * \param priv driver's private data
1539 * \param input index of available video input to get data from
1541 * \return TVI_CONTROL_TRUE success
1542 * \return TVI_CONTROL_FALSE error
1544 static int set_crossbar_input(priv_t
* priv
, int input
)
1547 int i
, nVideoDecoder
, nAudioDecoder
;
1548 long lInput
, lInputRelated
, lRelated
, lPhysicalType
, lOutputPins
,
1551 mp_msg(MSGT_TV
, MSGL_DBG4
, "tvi_dshow: Configuring crossbar\n");
1552 if (!priv
->pCrossbar
|| input
< 0
1553 || input
>= tv_available_inputs_count
)
1554 return TVI_CONTROL_FALSE
;
1556 OLE_CALL_ARGS(priv
->pCrossbar
, get_PinCounts
, &lOutputPins
, &lInputPins
);
1558 lInput
= tv_available_inputs
[input
];
1560 if (lInput
< 0 || lInput
>= lInputPins
)
1561 return TVI_CONTROL_FALSE
;
1563 OLE_CALL_ARGS(priv
->pCrossbar
, get_CrossbarPinInfo
, 1 /* input */ , lInput
,
1564 &lInputRelated
, &lPhysicalType
);
1566 nVideoDecoder
= nAudioDecoder
= -1;
1567 for (i
= 0; i
< lOutputPins
; i
++) {
1568 OLE_CALL_ARGS(priv
->pCrossbar
, get_CrossbarPinInfo
, 0 /*output */ , i
,
1569 &lRelated
, &lPhysicalType
);
1570 if (lPhysicalType
== PhysConn_Video_VideoDecoder
)
1572 if (lPhysicalType
== PhysConn_Audio_AudioDecoder
)
1575 if (nVideoDecoder
>= 0) {
1576 //connecting given input with video decoder
1577 hr
= OLE_CALL_ARGS(priv
->pCrossbar
, Route
, nVideoDecoder
, lInput
);
1579 mp_msg(MSGT_TV
,MSGL_ERR
,MSGTR_TVI_DS_UnableConnectInputVideoDecoder
, (unsigned int)hr
);
1580 return TVI_CONTROL_FALSE
;
1583 if (nAudioDecoder
>= 0 && lInputRelated
>= 0) {
1584 hr
= OLE_CALL_ARGS(priv
->pCrossbar
, Route
, nAudioDecoder
,
1587 mp_msg(MSGT_TV
,MSGL_ERR
,MSGTR_TVI_DS_UnableConnectInputAudioDecoder
, (unsigned int)hr
);
1588 return TVI_CONTROL_FALSE
;
1591 return TVI_CONTROL_TRUE
;
1595 * \brief adjusts video control (hue,saturation,contrast,brightess)
1597 * \param priv driver's private data
1598 * \param control which control to adjust
1599 * \param value new value for control (0-100)
1601 * \return TVI_CONTROL_TRUE success
1602 * \return TVI_CONTROL_FALSE error
1604 static int set_control(priv_t
* priv
, int control
, int value
)
1606 long lMin
, lMax
, lStepping
, lDefault
, lFlags
, lValue
;
1609 mp_msg(MSGT_TV
, MSGL_DBG4
, "tvi_dshow: set_control called\n");
1610 if (value
< -100 || value
> 100 || !priv
->pVideoProcAmp
)
1611 return TVI_CONTROL_FALSE
;
1613 hr
= OLE_CALL_ARGS(priv
->pVideoProcAmp
, GetRange
, control
,
1614 &lMin
, &lMax
, &lStepping
, &lDefault
, &lFlags
);
1615 if (FAILED(hr
) || lFlags
!= VideoProcAmp_Flags_Manual
)
1616 return TVI_CONTROL_FALSE
;
1618 lValue
= lMin
+ (value
+ 100) * (lMax
- lMin
) / 200;
1620 Workaround for ATI AIW 7500. The driver reports: max=255, stepping=256
1622 if (lStepping
> lMax
) {
1623 mp_msg(MSGT_TV
, MSGL_DBG3
,
1624 "tvi_dshow: Stepping (%ld) is bigger than max value (%ld) for control %d. Assuming 1\n",
1625 lStepping
, lMax
,control
);
1628 lValue
-= lValue
% lStepping
;
1629 hr
= OLE_CALL_ARGS(priv
->pVideoProcAmp
, Set
, control
, lValue
,
1630 VideoProcAmp_Flags_Manual
);
1632 return TVI_CONTROL_FALSE
;
1634 return TVI_CONTROL_TRUE
;
1638 * \brief get current value of video control (hue,saturation,contrast,brightess)
1640 * \param priv driver's private data
1641 * \param control which control to adjust
1642 * \param pvalue address of variable thar receives current value
1644 * \return TVI_CONTROL_TRUE success
1645 * \return TVI_CONTROL_FALSE error
1647 static int get_control(priv_t
* priv
, int control
, int *pvalue
)
1649 long lMin
, lMax
, lStepping
, lDefault
, lFlags
, lValue
;
1652 mp_msg(MSGT_TV
, MSGL_DBG4
, "tvi_dshow: get_control called\n");
1653 if (!pvalue
|| !priv
->pVideoProcAmp
)
1654 return TVI_CONTROL_FALSE
;
1656 hr
= OLE_CALL_ARGS(priv
->pVideoProcAmp
, GetRange
, control
,
1657 &lMin
, &lMax
, &lStepping
, &lDefault
, &lFlags
);
1659 return TVI_CONTROL_FALSE
;
1662 return TVI_CONTROL_TRUE
;
1665 hr
= OLE_CALL_ARGS(priv
->pVideoProcAmp
, Get
, control
, &lValue
, &lFlags
);
1667 return TVI_CONTROL_FALSE
;
1669 *pvalue
= 200 * (lValue
- lMin
) / (lMax
- lMin
) - 100;
1671 return TVI_CONTROL_TRUE
;
1675 * \brief create AM_MEDIA_TYPE structure, corresponding to given FourCC code and width/height/fps
1676 * \param fcc FourCC code for video format
1677 * \param width picture width
1678 * \param height pciture height
1679 * \param fps frames per second (required for bitrate calculation)
1681 * \return pointer to AM_MEDIA_TYPE structure if success, NULL - otherwise
1683 static AM_MEDIA_TYPE
* create_video_format(int fcc
, int width
, int height
, int fps
)
1687 VIDEOINFOHEADER vHdr
;
1689 /* Check given fcc in lookup table*/
1690 for(i
=0; img_fmt_list
[i
].fmt
&& img_fmt_list
[i
].fmt
!=fcc
; i
++) /* NOTHING */;
1691 if(!img_fmt_list
[i
].fmt
)
1694 memset(&mt
, 0, sizeof(AM_MEDIA_TYPE
));
1695 memset(&vHdr
, 0, sizeof(VIDEOINFOHEADER
));
1697 vHdr
.bmiHeader
.biSize
= sizeof(vHdr
.bmiHeader
);
1698 vHdr
.bmiHeader
.biWidth
= width
;
1699 vHdr
.bmiHeader
.biHeight
= height
;
1700 //FIXME: is biPlanes required too?
1701 //vHdr.bmiHeader.biPlanes = img_fmt_list[i].nPlanes;
1702 vHdr
.bmiHeader
.biBitCount
= img_fmt_list
[i
].nBits
;
1703 vHdr
.bmiHeader
.biCompression
= img_fmt_list
[i
].nCompression
;
1704 vHdr
.bmiHeader
.biSizeImage
= width
* height
* img_fmt_list
[i
].nBits
/ 8;
1705 vHdr
.dwBitRate
= vHdr
.bmiHeader
.biSizeImage
* 8 * fps
;
1707 mt
.pbFormat
= (char*)&vHdr
;
1708 mt
.cbFormat
= sizeof(vHdr
);
1710 mt
.majortype
= MEDIATYPE_Video
;
1711 mt
.subtype
= *img_fmt_list
[i
].subtype
;
1712 mt
.formattype
= FORMAT_VideoInfo
;
1714 mt
.bFixedSizeSamples
= 1;
1715 mt
.bTemporalCompression
= 0;
1716 mt
.lSampleSize
= vHdr
.bmiHeader
.biSizeImage
;
1718 return CreateMediaType(&mt
);
1722 * \brief extracts fcc,width,height from AM_MEDIA_TYPE
1724 * \param pmt pointer to AM_MEDIA_TYPE to extract data from
1725 * \param pfcc address of variable that receives FourCC
1726 * \param pwidth address of variable that receives width
1727 * \param pheight address of variable that recevies height
1729 * \return 1 if data extracted successfully, 0 - otherwise
1731 static int extract_video_format(AM_MEDIA_TYPE
* pmt
, int *pfcc
,
1732 int *pwidth
, int *pheight
)
1734 mp_msg(MSGT_TV
, MSGL_DBG4
, "tvi_dshow: extract_video_format called\n");
1739 if (memcmp(&(pmt
->formattype
), &FORMAT_VideoInfo
, 16) != 0)
1742 *pfcc
= subtype2imgfmt(&(pmt
->subtype
));
1744 *pwidth
= ((VIDEOINFOHEADER
*) pmt
->pbFormat
)->bmiHeader
.biWidth
;
1746 *pheight
= ((VIDEOINFOHEADER
*) pmt
->pbFormat
)->bmiHeader
.biHeight
;
1751 * \brief extracts samplerate,bits,channels from AM_MEDIA_TYPE
1753 * \param pmt pointer to AM_MEDIA_TYPE to extract data from
1754 * \param pfcc address of variable that receives samplerate
1755 * \param pwidth address of variable that receives number of bits per sample
1756 * \param pheight address of variable that recevies number of channels
1758 * \return 1 if data extracted successfully, 0 - otherwise
1760 static int extract_audio_format(AM_MEDIA_TYPE
* pmt
, int *psamplerate
,
1761 int *pbits
, int *pchannels
)
1763 mp_msg(MSGT_TV
, MSGL_DBG4
, "tvi_dshow: extract_audio_format called\n");
1768 if (memcmp(&(pmt
->formattype
), &FORMAT_WaveFormatEx
, 16) != 0)
1771 *psamplerate
= ((WAVEFORMATEX
*) pmt
->pbFormat
)->nSamplesPerSec
;
1773 *pbits
= ((WAVEFORMATEX
*) pmt
->pbFormat
)->wBitsPerSample
;
1775 *pchannels
= ((WAVEFORMATEX
*) pmt
->pbFormat
)->nChannels
;
1780 * \brief checks if AM_MEDIA_TYPE compatible with given samplerate,bits,channels
1782 * \param pmt pointer to AM_MEDIA_TYPE for check
1783 * \param samplerate audio samplerate
1784 * \param bits bits per sample
1785 * \param channels number of audio channels
1787 * \return 1 if AM_MEDIA_TYPE compatible
1790 static int check_audio_format(AM_MEDIA_TYPE
* pmt
, int samplerate
,
1791 int bits
, int channels
)
1793 mp_msg(MSGT_TV
, MSGL_DBG4
, "tvi_dshow: check_audio_format called\n");
1796 if (memcmp(&(pmt
->majortype
), &MEDIATYPE_Audio
, 16) != 0)
1798 if (memcmp(&(pmt
->subtype
), &MEDIASUBTYPE_PCM
, 16) != 0)
1800 if (memcmp(&(pmt
->formattype
), &FORMAT_WaveFormatEx
, 16) != 0)
1804 if (((WAVEFORMATEX
*) pmt
->pbFormat
)->nSamplesPerSec
!= samplerate
)
1806 if (((WAVEFORMATEX
*) pmt
->pbFormat
)->wBitsPerSample
!= bits
)
1809 && ((WAVEFORMATEX
*) pmt
->pbFormat
)->nChannels
!= channels
)
1816 * \brief checks if AM_MEDIA_TYPE compatible with given fcc,width,height
1818 * \param pmt pointer to AM_MEDIA_TYPE for check
1819 * \param fcc FourCC (compression)
1820 * \param width width of picture
1821 * \param height height of picture
1823 * \return 1 if AM_MEDIA_TYPE compatible
1827 * width and height are currently not used
1830 * add width/height check
1832 static int check_video_format(AM_MEDIA_TYPE
* pmt
, int fcc
, int width
,
1835 mp_msg(MSGT_TV
, MSGL_DBG4
, "tvi_dshow: check_video_format called\n");
1838 if (memcmp(&(pmt
->majortype
), &MEDIATYPE_Video
, 16) != 0)
1840 if (subtype2imgfmt(&(pmt
->subtype
)) != fcc
)
1846 * \brief converts DirectShow subtype to MPlayer's IMGFMT
1848 * \param subtype DirectShow subtype for video format
1850 * \return MPlayer's IMGFMT or 0 if error occured
1852 static int subtype2imgfmt(const GUID
* subtype
)
1855 for (i
= 0; img_fmt_list
[i
].fmt
; i
++) {
1856 if (memcmp(subtype
, img_fmt_list
[i
].subtype
, 16) == 0)
1857 return img_fmt_list
[i
].fmt
;
1863 * \brief prints filter name and it pins
1865 * \param pFilter - IBaseFilter to get data from
1867 * \return S_OK if success, error code otherwise
1869 static HRESULT
show_filter_info(IBaseFilter
* pFilter
)
1873 LPENUMPINS pEnum
= 0;
1875 PIN_DIRECTION ThisPinDir
;
1880 mp_msg(MSGT_TV
, MSGL_DBG4
, "tvi_dshow: show_filter_info called\n");
1881 memset(&fi
, 0, sizeof(fi
));
1882 memset(tmp
, 0, 200);
1884 OLE_CALL_ARGS(pFilter
, QueryFilterInfo
, &fi
);
1885 OLE_RELEASE_SAFE(fi
.pGraph
);
1886 wtoa(fi
.achName
, tmp
, 200);
1887 mp_msg(MSGT_TV
, MSGL_DBG2
, "tvi_dshow: BaseFilter (%p): Name=%s, Graph=%p output pins:",
1888 pFilter
, tmp
, fi
.pGraph
);
1889 hr
= OLE_CALL_ARGS(pFilter
, EnumPins
, &pEnum
);
1893 while (OLE_CALL_ARGS(pEnum
, Next
, 1, &pPin
, NULL
) == S_OK
) {
1894 memset(&pi
, 0, sizeof(pi
));
1895 memset(tmp
, 0, 200);
1896 OLE_CALL_ARGS(pPin
, QueryDirection
, &ThisPinDir
);
1897 if (ThisPinDir
== PINDIR_OUTPUT
) {
1898 OLE_CALL_ARGS(pPin
, QueryPinInfo
, &pi
);
1899 wtoa(pi
.achName
, tmp
, 200);
1900 OLE_RELEASE_SAFE(pi
.pFilter
);
1901 mp_msg(MSGT_TV
, MSGL_DBG2
, " %d=%s", i
, tmp
);
1902 mp_msg(MSGT_TV
, MSGL_DBG3
, " (%p)", pPin
);
1903 mp_msg(MSGT_TV
, MSGL_DBG2
, ";");
1904 OLE_RELEASE_SAFE(pPin
);
1908 mp_msg(MSGT_TV
, MSGL_DBG2
, "\n");
1909 OLE_RELEASE_SAFE(pEnum
);
1914 * \brief gets device's frendly in ANSI encoding
1916 * \param pM IMoniker interface, got in enumeration process
1917 * \param category device category
1919 * \return TVI_CONTROL_TRUE if operation succeded, TVI_CONTROL_FALSE - otherwise
1921 static int get_device_name(IMoniker
* pM
, char *pBuf
, int nLen
)
1925 IPropertyBag
*pPropBag
;
1926 hr
= OLE_CALL_ARGS(pM
, BindToStorage
, 0, 0, &IID_IPropertyBag
,(void *) &pPropBag
);
1928 mp_msg(MSGT_TV
, MSGL_DBG2
, "tvi_dshow: Call to BindToStorage failed\n");
1929 return TVI_CONTROL_FALSE
;
1932 hr
= OLE_CALL_ARGS(pPropBag
, Read
, L
"Description", (LPVARIANT
) & var
,
1935 hr
= OLE_CALL_ARGS(pPropBag
, Read
, L
"FriendlyName", (LPVARIANT
) & var
,
1938 OLE_RELEASE_SAFE(pPropBag
);
1939 if (SUCCEEDED(hr
)) {
1940 wtoa(var
.bstrVal
, pBuf
, nLen
);
1941 return TVI_CONTROL_TRUE
;
1943 return TVI_CONTROL_FALSE
;
1947 * \brief find capture device at given index
1949 * \param index device index to search for (-1 mean only print available)
1950 * \param category device category
1952 * \return IBaseFilter interface for capture device with given index
1954 * Sample values for category:
1955 * CLSID_VideoInputDeviceCategory - Video Capture Sources
1956 * CLSID_AudioInputDeviceCategory - Audio Capture Sources
1957 * See DirectShow SDK documentation for other possible values
1959 static IBaseFilter
*find_capture_device(int index
, REFCLSID category
)
1961 IBaseFilter
*pFilter
= NULL
;
1962 ICreateDevEnum
*pDevEnum
= NULL
;
1963 IEnumMoniker
*pClassEnum
= NULL
;
1968 char tmp
[DEVICE_NAME_MAX_LEN
+ 1];
1969 hr
= CoCreateInstance((GUID
*) & CLSID_SystemDeviceEnum
, NULL
,
1970 CLSCTX_INPROC_SERVER
, &IID_ICreateDevEnum
,
1971 (void *) &pDevEnum
);
1973 mp_msg(MSGT_TV
, MSGL_DBG2
, "tvi_dshow: Unable to create device enumerator\n");
1977 hr
= OLE_CALL_ARGS(pDevEnum
, CreateClassEnumerator
, category
, &pClassEnum
, 0);
1978 OLE_RELEASE_SAFE(pDevEnum
);
1980 mp_msg(MSGT_TV
, MSGL_DBG2
, "tvi_dshow: Unable to create class enumerator\n");
1983 if (hr
== S_FALSE
) {
1984 mp_msg(MSGT_TV
, MSGL_DBG2
, "tvi_dshow: No capture devices found\n");
1988 OLE_CALL(pClassEnum
,Reset
);
1989 for (i
= 0; OLE_CALL_ARGS(pClassEnum
, Next
, 1, &pM
, &cFetched
) == S_OK
; i
++) {
1990 if(get_device_name(pM
, tmp
, DEVICE_NAME_MAX_LEN
)!=TVI_CONTROL_TRUE
)
1991 mp_msg(MSGT_TV
, MSGL_ERR
, MSGTR_TVI_DS_UnableGetDeviceName
, i
);
1993 mp_msg(MSGT_TV
, MSGL_V
, MSGTR_TVI_DS_DeviceName
, i
, tmp
);
1994 if (index
!= -1 && i
== index
) {
1995 mp_msg(MSGT_TV
, MSGL_INFO
, MSGTR_TVI_DS_UsingDevice
, index
, tmp
);
1996 hr
= OLE_CALL_ARGS(pM
, BindToObject
, 0, 0, &IID_IBaseFilter
,(void *) &pFilter
);
2000 OLE_RELEASE_SAFE(pM
);
2002 if (index
!= -1 && !pFilter
) {
2003 mp_msg(MSGT_TV
, MSGL_ERR
, MSGTR_TVI_DS_DeviceNotFound
,
2006 OLE_RELEASE_SAFE(pClassEnum
);
2012 * \brief get array of available formats through call to IAMStreamConfig::GetStreamCaps
2014 * \praram[in] chain chain data structure
2016 * \return S_OK success
2017 * \return E_POINTER one of parameters is NULL
2018 * \return E_FAIL required size of buffer is unknown for given media type
2019 * \return E_OUTOFMEMORY not enough memory
2020 * \return other error code from called methods
2023 * last items of chain->arpmt and chain->arStreamCaps will be NULL
2025 static HRESULT
get_available_formats_stream(chain_t
*chain
)
2027 AM_MEDIA_TYPE
**arpmt
;
2034 mp_msg(MSGT_TV
, MSGL_DBG4
,
2035 "tvi_dshow: get_available_formats_stream called\n");
2037 if (!chain
->pStreamConfig
)
2040 hr
=OLE_CALL_ARGS(chain
->pStreamConfig
, GetNumberOfCapabilities
, &count
, &size
);
2042 mp_msg(MSGT_TV
, MSGL_DBG4
,
2043 "tvi_dshow: Call to GetNumberOfCapabilities failed (get_available_formats_stream)\n");
2046 if (chain
->type
== video
){
2047 if (size
!= sizeof(VIDEO_STREAM_CONFIG_CAPS
)) {
2048 mp_msg(MSGT_TV
, MSGL_DBG4
,
2049 "tvi_dshow: Wrong video structure size for GetNumberOfCapabilities (get_available_formats_stream)\n");
2052 } else if (chain
->type
== audio
){
2053 if (size
!= sizeof(AUDIO_STREAM_CONFIG_CAPS
)) {
2054 mp_msg(MSGT_TV
, MSGL_DBG4
,
2055 "tvi_dshow: Wrong audio structure size for GetNumberOfCapabilities (get_available_formats_stream)\n");
2059 mp_msg(MSGT_TV
, MSGL_ERR
, MSGTR_TVI_DS_UnsupportedMediaType
,"get_available_formats_stream");
2064 arpmt
= (AM_MEDIA_TYPE
**) malloc((count
+ 1) * sizeof(AM_MEDIA_TYPE
*));
2066 memset(arpmt
, 0, (count
+ 1) * sizeof(AM_MEDIA_TYPE
*));
2068 pBuf
= (void **) malloc((count
+ 1) * sizeof(void *));
2070 memset(pBuf
, 0, (count
+ 1) * sizeof(void *));
2072 for (i
= 0; i
< count
; i
++) {
2073 pBuf
[i
] = malloc(size
);
2078 hr
= OLE_CALL_ARGS(chain
->pStreamConfig
, GetStreamCaps
, i
,
2079 &(arpmt
[i
]), pBuf
[i
]);
2084 chain
->arpmt
= arpmt
;
2085 chain
->arStreamCaps
= pBuf
;
2091 for (i
= 0; i
< count
; i
++) {
2092 if (pBuf
&& pBuf
[i
])
2094 if (arpmt
&& arpmt
[i
])
2095 DeleteMediaType(arpmt
[i
]);
2102 mp_msg(MSGT_TV
, MSGL_DBG4
, "tvi_dshow: Call to GetStreamCaps failed (get_available_formats_stream)\n");
2105 return E_OUTOFMEMORY
;
2111 * \brief returns allocates an array and store available media formats for given pin type to it
2113 * \param pBuilder ICaptureGraphBuilder2 interface of graph builder
2114 * \param chain chain data structure
2116 * \return S_OK success
2117 * \return E_POINTER one of given pointers is null
2118 * \return apropriate error code otherwise
2120 static HRESULT
get_available_formats_pin(ICaptureGraphBuilder2
* pBuilder
,
2123 IEnumMediaTypes
*pEnum
;
2129 AM_MEDIA_TYPE
**arpmt
; //This will be real array
2130 VIDEO_STREAM_CONFIG_CAPS
*pVideoCaps
;
2131 AUDIO_STREAM_CONFIG_CAPS
*pAudioCaps
;
2134 mp_msg(MSGT_TV
, MSGL_DBG4
,
2135 "tvi_dshow: get_available_formats_pin called\n");
2136 if (!pBuilder
|| !chain
->pCaptureFilter
)
2139 if (!chain
->pCapturePin
)
2141 hr
= OLE_CALL_ARGS(pBuilder
, FindPin
,
2142 (IUnknown
*) chain
->pCaptureFilter
,
2143 PINDIR_OUTPUT
, &PIN_CATEGORY_CAPTURE
,
2144 chain
->majortype
, FALSE
, 0, &chain
->pCapturePin
);
2146 if (!chain
->pCapturePin
)
2149 if (chain
->type
== video
) {
2150 size
= sizeof(VIDEO_STREAM_CONFIG_CAPS
);
2151 } else if (chain
->type
== audio
) {
2152 size
= sizeof(AUDIO_STREAM_CONFIG_CAPS
);
2154 mp_msg(MSGT_TV
, MSGL_ERR
, MSGTR_TVI_DS_UnsupportedMediaType
,"get_available_formats_pin");
2158 hr
= OLE_CALL_ARGS(chain
->pCapturePin
, EnumMediaTypes
, &pEnum
);
2160 mp_msg(MSGT_TV
, MSGL_DBG4
,
2161 "tvi_dshow: Call to EnumMediaTypes failed (get_available_formats_pin)\n");
2164 for (i
= 0; OLE_CALL_ARGS(pEnum
, Next
, 1, &pmt
, &cFetched
) == S_OK
; i
++) {
2168 OLE_CALL(pEnum
,Reset
);
2172 (AM_MEDIA_TYPE
**) malloc((count
+ 1) * sizeof(AM_MEDIA_TYPE
*));
2174 return E_OUTOFMEMORY
;
2175 memset(arpmt
, 0, (count
+ 1) * sizeof(AM_MEDIA_TYPE
*));
2179 && OLE_CALL_ARGS(pEnum
, Next
, 1, &(arpmt
[i
]), &cFetched
) == S_OK
;
2182 OLE_RELEASE_SAFE(pEnum
);
2185 pBuf
= (void **) malloc((count
+ 1) * sizeof(void *));
2187 for (i
= 0; i
< count
; i
++)
2189 DeleteMediaType(arpmt
[i
]);
2191 return E_OUTOFMEMORY
;
2193 memset(pBuf
, 0, (count
+ 1) * sizeof(void *));
2195 for (i
= 0; i
< count
; i
++) {
2196 pBuf
[i
] = malloc(size
);
2199 memset(pBuf
[i
], 0, size
);
2201 if (chain
->type
== video
) {
2202 pVideoCaps
= (VIDEO_STREAM_CONFIG_CAPS
*) pBuf
[i
];
2203 extract_video_format(arpmt
[i
], NULL
, &p1
, &p2
);
2204 pVideoCaps
->MaxOutputSize
.cx
= pVideoCaps
->MinOutputSize
.cx
=
2206 pVideoCaps
->MaxOutputSize
.cy
= pVideoCaps
->MinOutputSize
.cy
=
2209 pAudioCaps
= (AUDIO_STREAM_CONFIG_CAPS
*) pBuf
[i
];
2210 extract_audio_format(arpmt
[i
], &p1
, &p2
, &p3
);
2211 pAudioCaps
->MaximumSampleFrequency
=
2212 pAudioCaps
->MinimumSampleFrequency
= p1
;
2213 pAudioCaps
->MaximumBitsPerSample
=
2214 pAudioCaps
->MinimumBitsPerSample
= p2
;
2215 pAudioCaps
->MaximumChannels
= pAudioCaps
->MinimumChannels
= p3
;
2220 for (i
= 0; i
< count
; i
++) {
2222 DeleteMediaType(arpmt
[i
]);
2228 return E_OUTOFMEMORY
;
2230 chain
->arpmt
= arpmt
;
2231 chain
->arStreamCaps
= pBuf
;
2237 *---------------------------------------------------------------------------------------
2241 *---------------------------------------------------------------------------------------
2244 * \brief fills given buffer with audio data (usually one block)
2246 * \param priv driver's private data structure
2247 * \param buffer buffer to store data to
2248 * \param len buffer's size in bytes (usually one block size)
2250 * \return audio pts if audio present, 1 - otherwise
2252 static double grab_audio_frame(priv_t
* priv
, char *buffer
, int len
)
2257 grabber_ringbuffer_t
*rb
= priv
->chains
[1]->rbuf
;
2258 grabber_ringbuffer_t
*vrb
= priv
->chains
[0]->rbuf
;
2260 if (!rb
|| !rb
->ringbuffer
)
2263 if(vrb
&& vrb
->tStart
<0){
2264 memset(buffer
,0,len
);
2267 if(vrb
&& rb
->tStart
<0)
2268 rb
->tStart
=vrb
->tStart
;
2270 if (len
< rb
->blocksize
)
2273 bytes
= rb
->blocksize
;
2275 mp_msg(MSGT_TV
, MSGL_DBG3
,"tvi_dshow: FillBuffer (audio) called. %d blocks in buffer, %d bytes requested\n",
2278 mp_msg(MSGT_TV
,MSGL_DBG4
,"tvi_dshow: waiting for frame\n");
2279 for(i
=0;i
<1000 && !rb
->count
;i
++) usec_sleep(1000);
2281 mp_msg(MSGT_TV
,MSGL_DBG4
,"tvi_dshow: waiting timeout\n");
2284 mp_msg(MSGT_TV
,MSGL_DBG4
,"tvi_dshow: got frame!\n");
2287 EnterCriticalSection(rb
->pMutex
);
2288 pts
=rb
->dpts
[rb
->head
]-rb
->tStart
;
2289 memcpy(buffer
, rb
->ringbuffer
[rb
->head
], bytes
);
2290 rb
->head
= (rb
->head
+ 1) % rb
->buffersize
;
2292 LeaveCriticalSection(rb
->pMutex
);
2297 * \brief returns audio frame size
2299 * \param priv driver's private data structure
2301 * \return audio block size if audio enabled and 1 - otherwise
2303 static int get_audio_framesize(priv_t
* priv
)
2305 if (!priv
->chains
[1]->rbuf
)
2306 return 1; //no audio
2307 mp_msg(MSGT_TV
,MSGL_DBG3
,"get_audio_framesize: %d\n",priv
->chains
[1]->rbuf
->blocksize
);
2308 return priv
->chains
[1]->rbuf
->blocksize
;
2311 #ifdef HAVE_TV_TELETEXT
2312 static int vbi_get_props(priv_t
* priv
,tt_stream_props
* ptsp
)
2315 return TVI_CONTROL_FALSE
;
2321 ptsp
->sampling_rate
=27e6
;
2322 ptsp
->samples_per_line
=720;
2327 ptsp
->bufsize
= ptsp
->samples_per_line
* (ptsp
->count
[0] + ptsp
->count
[1]);
2329 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",
2330 ptsp
->sampling_rate
,
2332 ptsp
->samples_per_line
,
2333 ptsp
->interlaced
?"Yes":"No",
2337 return TVI_CONTROL_TRUE
;
2340 static void vbi_grabber(priv_t
* priv
)
2342 grabber_ringbuffer_t
*rb
= priv
->chains
[2]->rbuf
;
2345 if (!rb
|| !rb
->ringbuffer
)
2348 buf
=calloc(1,rb
->blocksize
);
2349 for(i
=0; i
<23 && rb
->count
; i
++){
2350 memcpy(buf
,rb
->ringbuffer
[rb
->head
],rb
->blocksize
);
2351 teletext_control(priv
->priv_vbi
,TV_VBI_CONTROL_DECODE_PAGE
,&buf
);
2352 rb
->head
= (rb
->head
+ 1) % rb
->buffersize
;
2357 #endif //HAVE_TV_TELETEXT
2360 * \brief fills given buffer with video data (usually one frame)
2362 * \param priv driver's private data structure
2363 * \param buffer buffer to store data to
2364 * \param len buffer's size in bytes (usually one frame size)
2366 * \return frame size if video present, 0 - otherwise
2368 static double grab_video_frame(priv_t
* priv
, char *buffer
, int len
)
2373 grabber_ringbuffer_t
*rb
= priv
->chains
[0]->rbuf
;
2375 if (!rb
|| !rb
->ringbuffer
)
2377 if (len
< rb
->blocksize
)
2380 bytes
= rb
->blocksize
;
2382 mp_msg(MSGT_TV
, MSGL_DBG3
,"tvi_dshow: FillBuffer (video) called. %d blocks in buffer, %d bytes requested\n",
2385 mp_msg(MSGT_TV
,MSGL_DBG4
,"tvi_dshow: waiting for frame\n");
2386 for(i
=0;i
<1000 && !rb
->count
;i
++) usec_sleep(1000);
2388 mp_msg(MSGT_TV
,MSGL_DBG4
,"tvi_dshow: waiting timeout\n");
2391 mp_msg(MSGT_TV
,MSGL_DBG4
,"tvi_dshow: got frame!\n");
2393 EnterCriticalSection(rb
->pMutex
);
2395 rb
->tStart
=rb
->dpts
[rb
->head
];
2396 pts
=rb
->dpts
[rb
->head
]-rb
->tStart
;
2397 memcpy(buffer
, rb
->ringbuffer
[rb
->head
], bytes
);
2398 rb
->head
= (rb
->head
+ 1) % rb
->buffersize
;
2400 LeaveCriticalSection(rb
->pMutex
);
2402 #ifdef HAVE_TV_TELETEXT
2409 * \brief returns frame size
2411 * \param priv driver's private data structure
2413 * \return frame size if video present, 0 - otherwise
2415 static int get_video_framesize(priv_t
* priv
)
2417 // if(!priv->pmtVideo) return 1; //no video
2418 // return(priv->pmtVideo->lSampleSize);
2419 if (!priv
->chains
[0]->rbuf
)
2420 return 1; //no video
2421 mp_msg(MSGT_TV
,MSGL_DBG3
,"geT_video_framesize: %d\n",priv
->chains
[0]->rbuf
->blocksize
);
2422 return priv
->chains
[0]->rbuf
->blocksize
;
2426 * \brief calculate audio buffer size
2427 * \param video_buf_size size of video buffer in bytes
2428 * \param video_bitrate video bit rate
2429 * \param audio_bitrate audio bit rate
2430 * \return audio buffer isze in bytes
2432 * \remarks length of video buffer and resulted audio buffer calculated in
2433 * seconds will be the same.
2435 static inline int audio_buf_size_from_video(int video_buf_size
, int video_bitrate
, int audio_bitrate
)
2437 int audio_buf_size
= audio_bitrate
* (video_buf_size
/ video_bitrate
);
2438 mp_msg(MSGT_TV
,MSGL_DBG2
,"tvi_dshow: Audio capture buffer: %d * %d / %d = %d\n",
2439 audio_bitrate
,video_buf_size
,video_bitrate
,audio_buf_size
);
2440 return audio_buf_size
;
2444 * \brief common chain initialization routine
2445 * \param chain chain data structure
2447 * \note pCaptureFilter member should be initialized before call to this routine
2449 static HRESULT
init_chain_common(ICaptureGraphBuilder2
*pBuilder
, chain_t
*chain
)
2454 if(!chain
->pCaptureFilter
)
2457 show_filter_info(chain
->pCaptureFilter
);
2459 hr
= OLE_CALL_ARGS(pBuilder
, FindPin
,
2460 (IUnknown
*) chain
->pCaptureFilter
,
2461 PINDIR_OUTPUT
, chain
->pin_category
,
2462 chain
->majortype
, FALSE
, 0, &chain
->pCapturePin
);
2465 mp_msg(MSGT_TV
,MSGL_DBG2
, "tvi_dshow: FindPin(pCapturePin) call failed. Error:0x%x\n", (unsigned int)hr
);
2469 hr
= OLE_CALL_ARGS(pBuilder
, FindInterface
,
2470 chain
->pin_category
,
2472 chain
->pCaptureFilter
,
2473 &IID_IAMStreamConfig
,
2474 (void **) &(chain
->pStreamConfig
));
2476 chain
->pStreamConfig
= NULL
;
2479 Getting available video formats (last pointer in array will be NULL)
2480 First tryin to call IAMStreamConfig::GetStreamCaos. this will give us additional information such as
2481 min/max picture dimensions, etc. If this call fails trying IPIn::EnumMediaTypes with default
2484 hr
= get_available_formats_stream(chain
);
2486 mp_msg(MSGT_TV
, MSGL_DBG2
, "Unable to use IAMStreamConfig for retriving available formats (Error:0x%x). Using EnumMediaTypes instead\n", (unsigned int)hr
);
2487 hr
= get_available_formats_pin(pBuilder
, chain
);
2492 chain
->nFormatUsed
= 0;
2494 //If argument to CreateMediaType is NULL then result will be NULL too.
2495 chain
->pmt
= CreateMediaType(chain
->arpmt
[0]);
2497 for (i
= 0; chain
->arpmt
[i
]; i
++)
2498 DisplayMediaType("Available format", chain
->arpmt
[i
]);
2503 * \brief build video stream chain in graph
2504 * \param priv private data structure
2506 * \return S_OK if chain was built successfully, apropriate error code otherwise
2508 static HRESULT
build_video_chain(priv_t
*priv
)
2512 if(priv
->chains
[0]->rbuf
)
2515 if (priv
->chains
[0]->pStreamConfig
) {
2516 hr
= OLE_CALL_ARGS(priv
->chains
[0]->pStreamConfig
, SetFormat
, priv
->chains
[0]->pmt
);
2518 mp_msg(MSGT_TV
,MSGL_ERR
,MSGTR_TVI_DS_UnableSelectVideoFormat
, (unsigned int)hr
);
2522 priv
->chains
[0]->rbuf
=calloc(1,sizeof(grabber_ringbuffer_t
));
2523 if(!priv
->chains
[0]->rbuf
)
2524 return E_OUTOFMEMORY
;
2526 if (priv
->tv_param
->buffer_size
>= 0) {
2527 priv
->chains
[0]->rbuf
->buffersize
= priv
->tv_param
->buffer_size
;
2529 priv
->chains
[0]->rbuf
->buffersize
= 16;
2532 priv
->chains
[0]->rbuf
->buffersize
*= 1024 * 1024;
2533 hr
=build_sub_graph(priv
, priv
->chains
[0], &PIN_CATEGORY_CAPTURE
);
2535 mp_msg(MSGT_TV
, MSGL_ERR
, MSGTR_TVI_DS_UnableBuildVideoSubGraph
,(unsigned int)hr
);
2542 * \brief build audio stream chain in graph
2543 * \param priv private data structure
2545 * \return S_OK if chain was built successfully, apropriate error code otherwise
2547 static HRESULT
build_audio_chain(priv_t
*priv
)
2551 if(priv
->chains
[1]->rbuf
)
2554 if(priv
->immediate_mode
)
2557 if (priv
->chains
[1]->pStreamConfig
) {
2558 hr
= OLE_CALL_ARGS(priv
->chains
[1]->pStreamConfig
, SetFormat
,
2559 priv
->chains
[1]->pmt
);
2561 mp_msg(MSGT_TV
,MSGL_ERR
,MSGTR_TVI_DS_UnableSelectAudioFormat
, (unsigned int)hr
);
2565 if(priv
->chains
[1]->pmt
){
2566 priv
->chains
[1]->rbuf
=calloc(1,sizeof(grabber_ringbuffer_t
));
2567 if(!priv
->chains
[1]->rbuf
)
2568 return E_OUTOFMEMORY
;
2570 /* let the audio buffer be the same size (in seconds) than video one */
2571 priv
->chains
[1]->rbuf
->buffersize
=audio_buf_size_from_video(
2572 priv
->chains
[0]->rbuf
->buffersize
,
2573 (((VIDEOINFOHEADER
*) priv
->chains
[0]->pmt
->pbFormat
)->dwBitRate
),
2574 (((WAVEFORMATEX
*) (priv
->chains
[1]->pmt
->pbFormat
))->nAvgBytesPerSec
));
2576 hr
=build_sub_graph(priv
, priv
->chains
[1],&PIN_CATEGORY_CAPTURE
);
2578 mp_msg(MSGT_TV
, MSGL_ERR
, MSGTR_TVI_DS_UnableBuildAudioSubGraph
,(unsigned int)hr
);
2586 * \brief build VBI stream chain in graph
2587 * \param priv private data structure
2589 * \return S_OK if chain was built successfully, apropriate error code otherwise
2591 static HRESULT
build_vbi_chain(priv_t
*priv
)
2593 #ifdef HAVE_TV_TELETEXT
2596 if(priv
->chains
[2]->rbuf
)
2599 if(priv
->tv_param
->tdevice
)
2601 priv
->chains
[2]->rbuf
=calloc(1,sizeof(grabber_ringbuffer_t
));
2602 if(!priv
->chains
[2]->rbuf
)
2603 return E_OUTOFMEMORY
;
2605 init_ringbuffer(priv
->chains
[2]->rbuf
,24,priv
->tsp
.bufsize
);
2607 hr
=build_sub_graph(priv
, priv
->chains
[2],&PIN_CATEGORY_VBI
);
2609 mp_msg(MSGT_TV
, MSGL_ERR
, MSGTR_TVI_DS_UnableBuildVBISubGraph
,(unsigned int)hr
);
2618 * \brief playback/capture real start
2620 * \param priv driver's private data structure
2622 * \return 1 if success, 0 - otherwise
2624 * TODO: move some code from init() here
2626 static int start(priv_t
* priv
)
2630 hr
= build_video_chain(priv
);
2634 hr
= build_audio_chain(priv
);
2638 hr
= build_vbi_chain(priv
);
2643 Graph is ready to capture. Starting graph.
2645 if (mp_msg_test(MSGT_TV
, MSGL_DBG2
)) {
2646 mp_msg(MSGT_TV
, MSGL_DBG2
, "Debug pause 10sec\n");
2647 usec_sleep(10000000);
2648 mp_msg(MSGT_TV
, MSGL_DBG2
, "Debug pause end\n");
2650 if (!priv
->pMediaControl
) {
2651 mp_msg(MSGT_TV
,MSGL_ERR
,MSGTR_TVI_DS_UnableGetMediaControlInterface
,(unsigned int)E_POINTER
);
2654 hr
= OLE_CALL(priv
->pMediaControl
, Run
);
2656 mp_msg(MSGT_TV
,MSGL_ERR
,MSGTR_TVI_DS_UnableStartGraph
, (unsigned int)hr
);
2659 mp_msg(MSGT_TV
, MSGL_DBG2
, "tvi_dshow: Graph is started.\n");
2666 * \brief driver initialization
2668 * \param priv driver's private data structure
2670 * \return 1 if success, 0 - otherwise
2672 static int init(priv_t
* priv
)
2676 long lInput
, lTunerInput
;
2677 IEnumFilters
*pEnum
;
2678 IBaseFilter
*pFilter
;
2687 priv
->chains
[i
] = calloc(1, sizeof(chain_t
));
2689 priv
->chains
[0]->type
=video
;
2690 priv
->chains
[0]->majortype
=&MEDIATYPE_Video
;
2691 priv
->chains
[0]->pin_category
=&PIN_CATEGORY_CAPTURE
;
2692 priv
->chains
[1]->type
=audio
;
2693 priv
->chains
[1]->majortype
=&MEDIATYPE_Audio
;
2694 priv
->chains
[1]->pin_category
=&PIN_CATEGORY_CAPTURE
;
2695 priv
->chains
[2]->type
=vbi
;
2696 priv
->chains
[2]->majortype
=&MEDIATYPE_VBI
;
2697 priv
->chains
[2]->pin_category
=&PIN_CATEGORY_VBI
;
2700 hr
= CoCreateInstance((GUID
*) & CLSID_FilterGraph
, NULL
,
2701 CLSCTX_INPROC_SERVER
, &IID_IGraphBuilder
,
2702 (void **) &priv
->pGraph
);
2704 mp_msg(MSGT_TV
,MSGL_DBG2
, "tvi_dshow: CoCreateInstance(FilterGraph) call failed. Error:0x%x\n", (unsigned int)hr
);
2708 if (mp_msg_test(MSGT_TV
, MSGL_DBG2
)) {
2709 AddToRot((IUnknown
*) priv
->pGraph
, &(priv
->dwRegister
));
2712 hr
= CoCreateInstance((GUID
*) & CLSID_CaptureGraphBuilder2
, NULL
,
2713 CLSCTX_INPROC_SERVER
, &IID_ICaptureGraphBuilder2
,
2714 (void **) &priv
->pBuilder
);
2716 mp_msg(MSGT_TV
,MSGL_DBG2
, "tvi_dshow: CoCreateInstance(CaptureGraphBuilder) call failed. Error:0x%x\n", (unsigned int)hr
);
2720 hr
= OLE_CALL_ARGS(priv
->pBuilder
, SetFiltergraph
, priv
->pGraph
);
2722 mp_msg(MSGT_TV
,MSGL_ERR
, "tvi_dshow: SetFiltergraph call failed. Error:0x%x\n",(unsigned int)hr
);
2726 mp_msg(MSGT_TV
, MSGL_DBG2
, "tvi_dshow: Searching for available video capture devices\n");
2727 priv
->chains
[0]->pCaptureFilter
= find_capture_device(priv
->dev_index
, &CLSID_VideoInputDeviceCategory
);
2728 if(!priv
->chains
[0]->pCaptureFilter
){
2729 mp_msg(MSGT_TV
,MSGL_ERR
, MSGTR_TVI_DS_NoVideoCaptureDevice
);
2732 hr
= OLE_CALL_ARGS(priv
->pGraph
, AddFilter
, priv
->chains
[0]->pCaptureFilter
, NULL
);
2734 mp_msg(MSGT_TV
, MSGL_DBG2
, "tvi_dshow: Unable to add video capture device to Directshow graph. Error:0x%x\n", (unsigned int)hr
);
2737 mp_msg(MSGT_TV
, MSGL_DBG2
, "tvi_dshow: Searching for available audio capture devices\n");
2738 if (priv
->adev_index
!= -1) {
2739 priv
->chains
[1]->pCaptureFilter
= find_capture_device(priv
->adev_index
, &CLSID_AudioInputDeviceCategory
); //output available audio edevices
2740 if(!priv
->chains
[1]->pCaptureFilter
){
2741 mp_msg(MSGT_TV
,MSGL_ERR
, MSGTR_TVI_DS_NoAudioCaptureDevice
);
2745 hr
= OLE_CALL_ARGS(priv
->pGraph
, AddFilter
, priv
->chains
[1]->pCaptureFilter
, NULL
);
2747 mp_msg(MSGT_TV
,MSGL_DBG2
, "tvi_dshow: Unable to add audio capture device to Directshow graph. Error:0x%x\n", (unsigned int)hr
);
2751 hr
= OLE_QUERYINTERFACE(priv
->chains
[0]->pCaptureFilter
, IID_IBaseFilter
, priv
->chains
[1]->pCaptureFilter
);
2753 /* increase refrence counter for capture filter ad store pointer into vbi chain structure too */
2754 hr
= OLE_QUERYINTERFACE(priv
->chains
[0]->pCaptureFilter
, IID_IBaseFilter
, priv
->chains
[2]->pCaptureFilter
);
2756 hr
= OLE_QUERYINTERFACE(priv
->chains
[0]->pCaptureFilter
, IID_IAMVideoProcAmp
,priv
->pVideoProcAmp
);
2757 if (FAILED(hr
) && hr
!= E_NOINTERFACE
)
2758 mp_msg(MSGT_TV
, MSGL_DBG2
, "tvi_dshow: Get IID_IAMVideoProcAmp failed (0x%x).\n", (unsigned int)hr
);
2761 mp_msg(MSGT_TV
, MSGL_INFO
, MSGTR_TVI_DS_VideoAdjustigNotSupported
);
2762 priv
->pVideoProcAmp
= NULL
;
2765 hr
= OLE_CALL_ARGS(priv
->pBuilder
, FindInterface
,
2766 &PIN_CATEGORY_CAPTURE
,
2767 priv
->chains
[0]->majortype
,
2768 priv
->chains
[0]->pCaptureFilter
,
2769 &IID_IAMCrossbar
, (void **) &(priv
->pCrossbar
));
2771 mp_msg(MSGT_TV
, MSGL_INFO
, MSGTR_TVI_DS_SelectingInputNotSupported
);
2772 priv
->pCrossbar
= NULL
;
2775 if (priv
->tv_param
->amode
>= 0) {
2776 IAMTVAudio
*pTVAudio
;
2777 hr
= OLE_CALL_ARGS(priv
->pBuilder
, FindInterface
, NULL
, NULL
,priv
->chains
[0]->pCaptureFilter
,&IID_IAMTVAudio
, (void *) &pTVAudio
);
2779 switch (priv
->tv_param
->amode
) {
2781 hr
= OLE_CALL_ARGS(pTVAudio
, put_TVAudioMode
, AMTVAUDIO_MODE_MONO
);
2784 hr
= OLE_CALL_ARGS(pTVAudio
, put_TVAudioMode
, AMTVAUDIO_MODE_STEREO
);
2787 hr
= OLE_CALL_ARGS(pTVAudio
, put_TVAudioMode
,
2788 AMTVAUDIO_MODE_LANG_A
);
2791 hr
= OLE_CALL_ARGS(pTVAudio
, put_TVAudioMode
,
2792 AMTVAUDIO_MODE_LANG_B
);
2795 OLE_RELEASE_SAFE(pTVAudio
);
2797 mp_msg(MSGT_TV
, MSGL_WARN
, MSGTR_TVI_DS_UnableSetAudioMode
, priv
->tv_param
->amode
,(unsigned int)hr
);
2801 // Video chain initialization
2802 hr
= init_chain_common(priv
->pBuilder
, priv
->chains
[0]);
2807 Audio chain initialization
2808 Since absent audio stream is not fatal,
2809 at least one NULL pointer should be kept in format arrays
2810 (to avoid another additional check everywhere for array presence).
2812 hr
= init_chain_common(priv
->pBuilder
, priv
->chains
[1]);
2815 mp_msg(MSGT_TV
, MSGL_V
, "tvi_dshow: Unable to initialize audio chain (Error:0x%x). Audio disabled\n", (unsigned long)hr
);
2816 priv
->chains
[1]->arpmt
=calloc(1, sizeof(AM_MEDIA_TYPE
*));
2817 priv
->chains
[1]->arStreamCaps
=calloc(1, sizeof(void*));
2821 VBI chain initialization
2822 Since absent VBI stream is not fatal,
2823 at least one NULL pointer should be kept in format arrays
2824 (to avoid another additional check everywhere for array presence).
2826 hr
= init_chain_common(priv
->pBuilder
, priv
->chains
[2]);
2829 mp_msg(MSGT_TV
, MSGL_V
, "tvi_dshow: Unable to initialize VBI chain (Error:0x%x). Teletext disabled\n", (unsigned long)hr
);
2830 priv
->chains
[2]->arpmt
=calloc(1, sizeof(AM_MEDIA_TYPE
*));
2831 priv
->chains
[2]->arStreamCaps
=calloc(1, sizeof(void*));
2834 if (!priv
->chains
[0]->pStreamConfig
)
2835 mp_msg(MSGT_TV
, MSGL_INFO
, MSGTR_TVI_DS_ChangingWidthHeightNotSupported
);
2837 if (!priv
->chains
[0]->arpmt
[priv
->chains
[0]->nFormatUsed
]
2838 || !extract_video_format(priv
->chains
[0]->arpmt
[priv
->chains
[0]->nFormatUsed
],
2839 &(priv
->fcc
), &(priv
->width
),
2841 mp_msg(MSGT_TV
, MSGL_ERR
, MSGTR_TVI_DS_ErrorParsingVideoFormatStruct
);
2845 if (priv
->chains
[1]->arpmt
[priv
->chains
[1]->nFormatUsed
]) {
2846 if (!extract_audio_format(priv
->chains
[1]->pmt
, &(priv
->samplerate
), NULL
, NULL
)) {
2847 mp_msg(MSGT_TV
, MSGL_ERR
, MSGTR_TVI_DS_ErrorParsingAudioFormatStruct
);
2848 DisplayMediaType("audio format failed",priv
->chains
[1]->arpmt
[priv
->chains
[1]->nFormatUsed
]);
2853 hr
= OLE_QUERYINTERFACE(priv
->pGraph
, IID_IMediaControl
,priv
->pMediaControl
);
2855 mp_msg(MSGT_TV
,MSGL_ERR
, MSGTR_TVI_DS_UnableGetMediaControlInterface
,(unsigned int)hr
);
2858 hr
= OLE_CALL_ARGS(priv
->pBuilder
, FindInterface
,
2859 &PIN_CATEGORY_CAPTURE
, NULL
,
2860 priv
->chains
[0]->pCaptureFilter
,
2861 &IID_IAMTVTuner
, (void **) &(priv
->pTVTuner
));
2863 if (!priv
->pTVTuner
) {
2864 mp_msg(MSGT_TV
, MSGL_DBG2
, "tvi_dshow: Unable to access IAMTVTuner (0x%x)\n", (unsigned int)hr
);
2867 // shows Tuner capabilities
2868 get_capabilities(priv
);
2870 if (priv
->pTVTuner
) {
2871 hr
= OLE_CALL_ARGS(priv
->pTVTuner
, put_CountryCode
,
2872 chanlist2country(priv
->tv_param
->chanlist
));
2874 mp_msg(MSGT_TV
,MSGL_DBG2
, "tvi_dshow: Call to put_CountryCode failed. Error:0x%x\n",(unsigned int)hr
);
2877 hr
= OLE_CALL_ARGS(priv
->pTVTuner
, put_Mode
, AMTUNER_MODE_TV
);
2879 mp_msg(MSGT_TV
,MSGL_DBG2
, "tvi_dshow: Call to put_Mode failed. Error:0x%x\n",(unsigned int)hr
);
2883 hr
= OLE_CALL_ARGS(priv
->pTVTuner
, get_ConnectInput
, &lInput
);
2885 mp_msg(MSGT_TV
,MSGL_DBG2
, "tvi_dshow: Call to get_ConnectInput failed. Error:0x%x\n",(unsigned int)hr
);
2890 lTunerInput
= strstr(priv
->tv_param
->chanlist
, "cable") ? TunerInputCable
: TunerInputAntenna
;
2892 hr
= OLE_CALL_ARGS(priv
->pTVTuner
, put_InputType
, lInput
, lTunerInput
);
2894 mp_msg(MSGT_TV
,MSGL_DBG2
, "tvi_dshow: Call to put_InputType failed. Error:0x%x\n",(unsigned int)hr
);
2901 for VIVO cards we should check if preview pin is available on video capture device.
2902 If it is not, we have to connect Video Port Manager filter to VP pin of capture device filter.
2903 Otherwise we will get 0x8007001f (Device is not functioning properly) when attempting to start graph
2905 hr
= OLE_CALL_ARGS(priv
->pBuilder
, FindPin
,
2906 (IUnknown
*) priv
->chains
[0]->pCaptureFilter
,
2908 &PIN_CATEGORY_VIDEOPORT
, NULL
, FALSE
,
2909 0, (IPin
**) & pVPOutPin
);
2910 if (SUCCEEDED(hr
)) {
2911 hr
= OLE_CALL_ARGS(priv
->pGraph
, Render
, pVPOutPin
);
2912 OLE_RELEASE_SAFE(pVPOutPin
);
2915 mp_msg(MSGT_TV
,MSGL_ERR
, MSGTR_TVI_DS_UnableTerminateVPPin
, (unsigned int)hr
);
2920 OLE_CALL_ARGS(priv
->pGraph
, EnumFilters
, &pEnum
);
2921 while (OLE_CALL_ARGS(pEnum
, Next
, 1, &pFilter
, NULL
) == S_OK
) {
2922 LPVIDEOWINDOW pVideoWindow
;
2923 hr
= OLE_QUERYINTERFACE(pFilter
, IID_IVideoWindow
, pVideoWindow
);
2926 if(priv
->tv_param
->hidden_vp_renderer
){
2927 OLE_CALL_ARGS(pVideoWindow
,put_Visible
,/* OAFALSE*/ 0);
2928 OLE_CALL_ARGS(pVideoWindow
,put_AutoShow
,/* OAFALSE*/ 0);
2931 OLE_CALL_ARGS(priv
->pGraph
, RemoveFilter
, pFilter
);
2933 OLE_RELEASE_SAFE(pVideoWindow
);
2935 OLE_RELEASE_SAFE(pFilter
);
2937 OLE_RELEASE_SAFE(pEnum
);
2938 if(priv
->tv_param
->system_clock
)
2940 LPREFERENCECLOCK rc
;
2942 hr
= CoCreateInstance((GUID
*) & CLSID_SystemClock
, NULL
,
2943 CLSCTX_INPROC_SERVER
, &IID_IReferenceClock
,
2946 OLE_QUERYINTERFACE(priv
->pBuilder
,IID_IBaseFilter
,pBF
);
2947 OLE_CALL_ARGS(pBF
,SetSyncSource
,rc
);
2949 #ifdef HAVE_TV_TELETEXT
2950 if(vbi_get_props(priv
,&(priv
->tsp
))!=TVI_CONTROL_TRUE
)
2957 mp_msg(MSGT_TV
,MSGL_ERR
, MSGTR_TVI_DS_GraphInitFailure
);
2964 * \brief chain uninitialization
2965 * \param chain chain data structure
2967 static void destroy_chain(chain_t
*chain
)
2974 OLE_RELEASE_SAFE(chain
->pStreamConfig
);
2975 OLE_RELEASE_SAFE(chain
->pCaptureFilter
);
2976 OLE_RELEASE_SAFE(chain
->pCSGCB
);
2977 OLE_RELEASE_SAFE(chain
->pCapturePin
);
2978 OLE_RELEASE_SAFE(chain
->pSGIn
);
2979 OLE_RELEASE_SAFE(chain
->pSG
);
2980 OLE_RELEASE_SAFE(chain
->pSGF
);
2983 DeleteMediaType(chain
->pmt
);
2986 for (i
= 0; chain
->arpmt
[i
]; i
++) {
2987 DeleteMediaType(chain
->arpmt
[i
]);
2992 if (chain
->arStreamCaps
) {
2993 for (i
= 0; chain
->arStreamCaps
[i
]; i
++) {
2994 free(chain
->arStreamCaps
[i
]);
2996 free(chain
->arStreamCaps
);
3000 destroy_ringbuffer(chain
->rbuf
);
3007 * \brief driver uninitialization
3009 * \param priv driver's private data structure
3013 static int uninit(priv_t
* priv
)
3019 if (priv
->dwRegister
) {
3020 RemoveFromRot(priv
->dwRegister
);
3022 #ifdef HAVE_TV_TELETEXT
3023 teletext_control(priv
->priv_vbi
,TV_VBI_CONTROL_STOP
,(void*)1);
3025 //stop audio grabber thread
3027 if (priv
->state
&& priv
->pMediaControl
) {
3028 OLE_CALL(priv
->pMediaControl
, Stop
);
3030 OLE_RELEASE_SAFE(priv
->pMediaControl
);
3034 if (priv
->chains
[0]->pCaptureFilter
)
3035 OLE_CALL_ARGS(priv
->pGraph
, RemoveFilter
, priv
->chains
[0]->pCaptureFilter
);
3036 if (priv
->chains
[1]->pCaptureFilter
)
3037 OLE_CALL_ARGS(priv
->pGraph
, RemoveFilter
, priv
->chains
[1]->pCaptureFilter
);
3039 OLE_RELEASE_SAFE(priv
->pCrossbar
);
3040 OLE_RELEASE_SAFE(priv
->pVideoProcAmp
);
3041 OLE_RELEASE_SAFE(priv
->pGraph
);
3042 OLE_RELEASE_SAFE(priv
->pBuilder
);
3043 if(priv
->freq_table
){
3044 priv
->freq_table_len
=-1;
3045 free(priv
->freq_table
);
3046 priv
->freq_table
=NULL
;
3051 destroy_chain(priv
->chains
[i
]);
3052 priv
->chains
[i
] = NULL
;
3059 * \brief driver pre-initialization
3061 * \param device string, containing device name in form "x[.y]", where x is video capture device
3062 * (default: 0, first available); y (if given) sets audio capture device
3064 * \return 1 if success,0 - otherwise
3066 static tvi_handle_t
*tvi_init_dshow(tv_param_t
* tv_param
)
3078 memset(priv
, 0, sizeof(priv_t
));
3079 priv
->direct_setfreq_call
= 1; //first using direct call. if it fails, workaround will be enabled
3080 priv
->direct_getfreq_call
= 1; //first using direct call. if it fails, workaround will be enabled
3081 priv
->adev_index
= -1;
3082 priv
->freq_table_len
=-1;
3083 priv
->tv_param
=tv_param
;
3085 if (tv_param
->device
) {
3086 if (sscanf(tv_param
->device
, "%d", &a
) == 1) {
3087 priv
->dev_index
= a
;
3089 mp_msg(MSGT_TV
, MSGL_ERR
, MSGTR_TVI_DS_WrongDeviceParam
, tv_param
->device
);
3093 if (priv
->dev_index
< 0) {
3094 mp_msg(MSGT_TV
, MSGL_ERR
, MSGTR_TVI_DS_WrongDeviceIndex
, a
);
3099 if (tv_param
->adevice
) {
3100 if (sscanf(tv_param
->adevice
, "%d", &a
) == 1) {
3101 priv
->adev_index
= a
;
3103 mp_msg(MSGT_TV
, MSGL_ERR
, MSGTR_TVI_DS_WrongADeviceParam
, tv_param
->adevice
);
3107 if (priv
->dev_index
< 0) {
3108 mp_msg(MSGT_TV
, MSGL_ERR
, MSGTR_TVI_DS_WrongADeviceIndex
, a
);
3117 * \brief driver's ioctl handler
3119 * \param priv driver's private data structure
3120 * \param cmd ioctl command
3121 * \param arg ioct command's parameter
3123 * \return TVI_CONTROL_TRUE if success
3124 * \return TVI_CONTROL_FALSE if failure
3125 * \return TVI_CONTROL_UNKNOWN if unknowm cmd called
3127 static int control(priv_t
* priv
, int cmd
, void *arg
)
3131 case TVI_CONTROL_VID_SET_FORMAT
:
3135 int result
= TVI_CONTROL_TRUE
;
3138 return TVI_CONTROL_FALSE
;
3141 if(!priv
->chains
[0]->arpmt
)
3142 return TVI_CONTROL_FALSE
;
3143 for (i
= 0; priv
->chains
[0]->arpmt
[i
]; i
++)
3144 if (check_video_format
3145 (priv
->chains
[0]->arpmt
[i
], fcc
, priv
->width
, priv
->height
))
3147 if (!priv
->chains
[0]->arpmt
[i
])
3150 VIDEOINFOHEADER
* Vhdr
= NULL
;
3153 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
));
3155 if (priv
->chains
[0]->arpmt
[0])
3156 Vhdr
= (VIDEOINFOHEADER
*) priv
->chains
[0]->arpmt
[0]->pbFormat
;
3158 if(Vhdr
&& Vhdr
->bmiHeader
.biSizeImage
)
3159 fps
= Vhdr
->dwBitRate
/ (8 * Vhdr
->bmiHeader
.biSizeImage
);
3161 pmt
=create_video_format(fcc
, priv
->width
, priv
->height
, fps
);
3164 mp_msg(MSGT_TV
, MSGL_V
, "tvi_dshow: Unable to create AM_MEDIA_TYPE structure for given format\n");
3165 return TVI_CONTROL_FALSE
;
3167 priv
->chains
[0]->arpmt
=realloc(priv
->chains
[0]->arpmt
, (i
+2)*sizeof(AM_MEDIA_TYPE
*));
3168 priv
->chains
[0]->arpmt
[i
+1] = NULL
;
3169 priv
->chains
[0]->arpmt
[i
] = pmt
;
3171 priv
->chains
[0]->arStreamCaps
=realloc(priv
->chains
[0]->arStreamCaps
, (i
+2)*sizeof(void*));
3172 priv
->chains
[0]->arpmt
[i
+1] = NULL
;
3174 result
= TVI_CONTROL_FALSE
;
3178 tmp
=priv
->chains
[0]->arpmt
[i
];
3179 tmp2
=priv
->chains
[0]->arStreamCaps
[i
];
3182 priv
->chains
[0]->arpmt
[j
] = priv
->chains
[0]->arpmt
[j
-1];
3183 priv
->chains
[0]->arStreamCaps
[j
] = priv
->chains
[0]->arStreamCaps
[j
-1];
3185 priv
->chains
[0]->arpmt
[0] = tmp
;
3186 priv
->chains
[0]->arStreamCaps
[0] = tmp2
;
3188 priv
->chains
[0]->nFormatUsed
= 0;
3190 if (priv
->chains
[0]->pmt
)
3191 DeleteMediaType(priv
->chains
[0]->pmt
);
3192 priv
->chains
[0]->pmt
=
3193 CreateMediaType(priv
->chains
[0]->arpmt
[priv
->chains
[0]->nFormatUsed
]);
3194 DisplayMediaType("VID_SET_FORMAT", priv
->chains
[0]->pmt
);
3196 Setting width & height to preferred by driver values
3198 extract_video_format(priv
->chains
[0]->arpmt
[priv
->chains
[0]->nFormatUsed
],
3199 &(priv
->fcc
), &(priv
->width
),
3203 case TVI_CONTROL_VID_GET_FORMAT
:
3205 if(!priv
->chains
[0]->pmt
)
3206 return TVI_CONTROL_FALSE
;
3208 Build video chain (for video format negotiation).
3209 If this was done before, routine will do nothing.
3211 build_video_chain(priv
);
3212 DisplayMediaType("VID_GET_FORMAT", priv
->chains
[0]->pmt
);
3214 *(int *) arg
= priv
->fcc
;
3215 return (TVI_CONTROL_TRUE
);
3217 return (TVI_CONTROL_FALSE
);
3219 case TVI_CONTROL_VID_SET_WIDTH
:
3221 VIDEO_STREAM_CONFIG_CAPS
*pCaps
;
3222 VIDEOINFOHEADER
*Vhdr
;
3223 int width
= *(int *) arg
;
3225 return TVI_CONTROL_FALSE
;
3227 pCaps
= priv
->chains
[0]->arStreamCaps
[priv
->chains
[0]->nFormatUsed
];
3229 return TVI_CONTROL_FALSE
;
3230 if (width
< pCaps
->MinOutputSize
.cx
3231 || width
> pCaps
->MaxOutputSize
.cx
)
3232 return TVI_CONTROL_FALSE
;
3234 if (width
% pCaps
->OutputGranularityX
)
3235 return TVI_CONTROL_FALSE
;
3237 if (!priv
->chains
[0]->pmt
|| !priv
->chains
[0]->pmt
->pbFormat
)
3238 return TVI_CONTROL_FALSE
;
3239 Vhdr
= (VIDEOINFOHEADER
*) priv
->chains
[0]->pmt
->pbFormat
;
3240 Vhdr
->bmiHeader
.biWidth
= width
;
3241 priv
->chains
[0]->pmt
->lSampleSize
= Vhdr
->bmiHeader
.biSizeImage
=
3242 labs(Vhdr
->bmiHeader
.biBitCount
* Vhdr
->bmiHeader
.biWidth
*
3243 Vhdr
->bmiHeader
.biHeight
) >> 3;
3245 priv
->width
= width
;
3247 return (TVI_CONTROL_TRUE
);
3249 case TVI_CONTROL_VID_GET_WIDTH
:
3252 *(int *) arg
= priv
->width
;
3253 return (TVI_CONTROL_TRUE
);
3255 return TVI_CONTROL_FALSE
;
3257 case TVI_CONTROL_VID_CHK_WIDTH
:
3259 VIDEO_STREAM_CONFIG_CAPS
*pCaps
;
3260 int width
= *(int *) arg
;
3261 pCaps
= priv
->chains
[0]->arStreamCaps
[priv
->chains
[0]->nFormatUsed
];
3263 return TVI_CONTROL_FALSE
;
3264 if (width
< pCaps
->MinOutputSize
.cx
3265 || width
> pCaps
->MaxOutputSize
.cx
)
3266 return TVI_CONTROL_FALSE
;
3268 if (width
% pCaps
->OutputGranularityX
)
3269 return TVI_CONTROL_FALSE
;
3270 return (TVI_CONTROL_TRUE
);
3272 case TVI_CONTROL_VID_SET_HEIGHT
:
3274 VIDEO_STREAM_CONFIG_CAPS
*pCaps
;
3275 VIDEOINFOHEADER
*Vhdr
;
3276 int height
= *(int *) arg
;
3278 return TVI_CONTROL_FALSE
;
3280 pCaps
= priv
->chains
[0]->arStreamCaps
[priv
->chains
[0]->nFormatUsed
];
3282 return TVI_CONTROL_FALSE
;
3283 if (height
< pCaps
->MinOutputSize
.cy
3284 || height
> pCaps
->MaxOutputSize
.cy
)
3285 return TVI_CONTROL_FALSE
;
3287 if (height
% pCaps
->OutputGranularityY
)
3288 return TVI_CONTROL_FALSE
;
3290 if (!priv
->chains
[0]->pmt
|| !priv
->chains
[0]->pmt
->pbFormat
)
3291 return TVI_CONTROL_FALSE
;
3292 Vhdr
= (VIDEOINFOHEADER
*) priv
->chains
[0]->pmt
->pbFormat
;
3294 if (Vhdr
->bmiHeader
.biHeight
< 0)
3295 Vhdr
->bmiHeader
.biHeight
= -height
;
3297 Vhdr
->bmiHeader
.biHeight
= height
;
3298 priv
->chains
[0]->pmt
->lSampleSize
= Vhdr
->bmiHeader
.biSizeImage
=
3299 labs(Vhdr
->bmiHeader
.biBitCount
* Vhdr
->bmiHeader
.biWidth
*
3300 Vhdr
->bmiHeader
.biHeight
) >> 3;
3302 priv
->height
= height
;
3303 return (TVI_CONTROL_TRUE
);
3305 case TVI_CONTROL_VID_GET_HEIGHT
:
3308 *(int *) arg
= priv
->height
;
3309 return (TVI_CONTROL_TRUE
);
3311 return TVI_CONTROL_FALSE
;
3313 case TVI_CONTROL_VID_CHK_HEIGHT
:
3315 VIDEO_STREAM_CONFIG_CAPS
*pCaps
;
3316 int height
= *(int *) arg
;
3317 pCaps
= priv
->chains
[0]->arStreamCaps
[priv
->chains
[0]->nFormatUsed
];
3319 return TVI_CONTROL_FALSE
;
3320 if (height
< pCaps
->MinOutputSize
.cy
3321 || height
> pCaps
->MaxOutputSize
.cy
)
3322 return TVI_CONTROL_FALSE
;
3324 if (height
% pCaps
->OutputGranularityY
)
3325 return TVI_CONTROL_FALSE
;
3327 return (TVI_CONTROL_TRUE
);
3329 case TVI_CONTROL_IS_AUDIO
:
3330 if (!priv
->chains
[1]->pmt
)
3331 return TVI_CONTROL_FALSE
;
3333 return TVI_CONTROL_TRUE
;
3334 case TVI_CONTROL_IS_VIDEO
:
3335 return TVI_CONTROL_TRUE
;
3336 case TVI_CONTROL_AUD_GET_FORMAT
:
3338 *(int *) arg
= AF_FORMAT_S16_LE
;
3339 if (!priv
->chains
[1]->pmt
)
3340 return TVI_CONTROL_FALSE
;
3342 return TVI_CONTROL_TRUE
;
3344 case TVI_CONTROL_AUD_GET_CHANNELS
:
3346 *(int *) arg
= priv
->channels
;
3347 if (!priv
->chains
[1]->pmt
)
3348 return TVI_CONTROL_FALSE
;
3350 return TVI_CONTROL_TRUE
;
3352 case TVI_CONTROL_AUD_SET_SAMPLERATE
:
3356 return TVI_CONTROL_FALSE
;
3357 if (!priv
->chains
[1]->arpmt
[0])
3358 return TVI_CONTROL_FALSE
;
3360 samplerate
= *(int *) arg
;;
3362 for (i
= 0; priv
->chains
[1]->arpmt
[i
]; i
++)
3363 if (check_audio_format
3364 (priv
->chains
[1]->arpmt
[i
], samplerate
, 16, priv
->channels
))
3366 if (!priv
->chains
[1]->arpmt
[i
]) {
3367 //request not found. failing back to first available
3368 mp_msg(MSGT_TV
, MSGL_WARN
, MSGTR_TVI_DS_SamplerateNotsupported
, samplerate
);
3371 if (priv
->chains
[1]->pmt
)
3372 DeleteMediaType(priv
->chains
[1]->pmt
);
3373 priv
->chains
[1]->pmt
= CreateMediaType(priv
->chains
[1]->arpmt
[i
]);
3374 extract_audio_format(priv
->chains
[1]->arpmt
[i
], &(priv
->samplerate
),
3375 NULL
, &(priv
->channels
));
3376 return TVI_CONTROL_TRUE
;
3378 case TVI_CONTROL_AUD_GET_SAMPLERATE
:
3380 *(int *) arg
= priv
->samplerate
;
3381 if (!priv
->samplerate
)
3382 return TVI_CONTROL_FALSE
;
3383 if (!priv
->chains
[1]->pmt
)
3384 return TVI_CONTROL_FALSE
;
3386 return TVI_CONTROL_TRUE
;
3388 case TVI_CONTROL_AUD_GET_SAMPLESIZE
:
3391 if (!priv
->chains
[1]->pmt
)
3392 return TVI_CONTROL_FALSE
;
3393 if (!priv
->chains
[1]->pmt
->pbFormat
)
3394 return TVI_CONTROL_FALSE
;
3395 pWF
= (WAVEFORMATEX
*) priv
->chains
[1]->pmt
->pbFormat
;
3396 *(int *) arg
= pWF
->wBitsPerSample
/ 8;
3397 return TVI_CONTROL_TRUE
;
3399 case TVI_CONTROL_IS_TUNER
:
3401 if (!priv
->pTVTuner
)
3402 return TVI_CONTROL_FALSE
;
3404 return (TVI_CONTROL_TRUE
);
3406 case TVI_CONTROL_TUN_SET_NORM
:
3408 IAMAnalogVideoDecoder
*pVD
;
3415 if (i
< 0 || i
>= tv_available_norms_count
)
3416 return TVI_CONTROL_FALSE
;
3417 lAnalogFormat
= tv_norms
[tv_available_norms
[i
]].index
;
3419 hr
= OLE_QUERYINTERFACE(priv
->chains
[0]->pCaptureFilter
,IID_IAMAnalogVideoDecoder
, pVD
);
3421 return TVI_CONTROL_FALSE
;
3422 hr
= OLE_CALL_ARGS(pVD
, put_TVFormat
, lAnalogFormat
);
3423 OLE_RELEASE_SAFE(pVD
);
3425 return (TVI_CONTROL_FALSE
);
3427 return (TVI_CONTROL_TRUE
);
3429 case TVI_CONTROL_TUN_GET_NORM
:
3434 IAMAnalogVideoDecoder
*pVD
;
3436 hr
= OLE_QUERYINTERFACE(priv
->chains
[0]->pCaptureFilter
,IID_IAMAnalogVideoDecoder
, pVD
);
3438 hr
= OLE_CALL_ARGS(pVD
, get_TVFormat
, &lAnalogFormat
);
3439 OLE_RELEASE_SAFE(pVD
);
3442 if (FAILED(hr
)) { //trying another method
3443 if (!priv
->pTVTuner
)
3444 return TVI_CONTROL_FALSE
;
3445 hr
=OLE_CALL_ARGS(priv
->pTVTuner
, get_TVFormat
, &lAnalogFormat
);
3447 return TVI_CONTROL_FALSE
;
3449 for (i
= 0; i
< tv_available_norms_count
; i
++) {
3450 if (tv_norms
[tv_available_norms
[i
]].index
== lAnalogFormat
) {
3451 *(int *) arg
= i
+ 1;
3452 return TVI_CONTROL_TRUE
;
3455 return (TVI_CONTROL_FALSE
);
3457 case TVI_CONTROL_SPC_GET_NORMID
:
3460 if (!priv
->pTVTuner
)
3461 return TVI_CONTROL_FALSE
;
3462 for (i
= 0; i
< tv_available_norms_count
; i
++) {
3464 (tv_norms
[tv_available_norms
[i
]].name
, (char *) arg
)) {
3465 *(int *) arg
= i
+ 1;
3466 return TVI_CONTROL_TRUE
;
3469 return TVI_CONTROL_FALSE
;
3471 case TVI_CONTROL_SPC_SET_INPUT
:
3473 return set_crossbar_input(priv
, *(int *) arg
);
3475 case TVI_CONTROL_TUN_GET_FREQ
:
3477 unsigned long lFreq
;
3479 if (!priv
->pTVTuner
)
3480 return TVI_CONTROL_FALSE
;
3482 ret
= get_frequency(priv
, &lFreq
);
3483 lFreq
= lFreq
* 16 / 1000000; //convert from Hz to 1/16 MHz units
3485 *(unsigned long *) arg
= lFreq
;
3488 case TVI_CONTROL_TUN_SET_FREQ
:
3490 unsigned long nFreq
= *(unsigned long *) arg
;
3491 if (!priv
->pTVTuner
)
3492 return TVI_CONTROL_FALSE
;
3494 nFreq
= 1000000 * nFreq
/ 16; //convert from 1/16 MHz units to Hz
3495 return set_frequency(priv
, nFreq
);
3497 case TVI_CONTROL_VID_SET_HUE
:
3498 return set_control(priv
, VideoProcAmp_Hue
, *(int *) arg
);
3499 case TVI_CONTROL_VID_GET_HUE
:
3500 return get_control(priv
, VideoProcAmp_Hue
, (int *) arg
);
3501 case TVI_CONTROL_VID_SET_CONTRAST
:
3502 return set_control(priv
, VideoProcAmp_Contrast
, *(int *) arg
);
3503 case TVI_CONTROL_VID_GET_CONTRAST
:
3504 return get_control(priv
, VideoProcAmp_Contrast
, (int *) arg
);
3505 case TVI_CONTROL_VID_SET_SATURATION
:
3506 return set_control(priv
, VideoProcAmp_Saturation
, *(int *) arg
);
3507 case TVI_CONTROL_VID_GET_SATURATION
:
3508 return get_control(priv
, VideoProcAmp_Saturation
, (int *) arg
);
3509 case TVI_CONTROL_VID_SET_BRIGHTNESS
:
3510 return set_control(priv
, VideoProcAmp_Brightness
, *(int *) arg
);
3511 case TVI_CONTROL_VID_GET_BRIGHTNESS
:
3512 return get_control(priv
, VideoProcAmp_Brightness
, (int *) arg
);
3514 case TVI_CONTROL_VID_GET_FPS
:
3516 VIDEOINFOHEADER
*Vhdr
;
3517 if (!priv
->chains
[0]->pmt
)
3518 return TVI_CONTROL_FALSE
;
3519 if (!priv
->chains
[0]->pmt
->pbFormat
)
3520 return TVI_CONTROL_FALSE
;
3521 Vhdr
= (VIDEOINFOHEADER
*) priv
->chains
[0]->pmt
->pbFormat
;
3523 (1.0 * Vhdr
->dwBitRate
) / (Vhdr
->bmiHeader
.biSizeImage
* 8);
3524 return TVI_CONTROL_TRUE
;
3526 case TVI_CONTROL_IMMEDIATE
:
3527 priv
->immediate_mode
= 1;
3528 return TVI_CONTROL_TRUE
;
3529 #ifdef HAVE_TV_TELETEXT
3530 case TVI_CONTROL_VBI_INIT
:
3534 if(teletext_control(NULL
,TV_VBI_CONTROL_START
,&ptr
)==TVI_CONTROL_TRUE
)
3537 priv
->priv_vbi
=NULL
;
3538 return TVI_CONTROL_TRUE
;
3541 return teletext_control(priv
->priv_vbi
,cmd
,arg
);
3544 return (TVI_CONTROL_UNKNOWN
);