2 * TV support under Win32
4 * (C) 2007 Vladimir Voroshilov <voroshil@gmail.com>
6 * Based on tvi_dummy.c with help of tv.c, tvi_v4l2.c code.
8 * This file is part of MPlayer.
10 * MPlayer is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * MPlayer is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License along
21 * with MPlayer; if not, write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 * WARNING: This is alpha code!
29 * * Watching TV under Win32 using WDM Capture driver and DirectShow
30 * * Grabbing synchronized audio/video with mencoder (synchronization is beeing done by DirectShow)
31 * * If device driver provides IAMStreamConfig interface, user can choose width/height with "-tv height=<h>:width=<w>"
32 * * Adjusting BRIGHTNESS,HUE,SATURATION,CONTRAST if supported by device
33 * * Selecting Tuner,S-Video,... as media source
34 * * User can select used video capture device, passing -tv device=<dev#>
35 * * User can select used audio input, passing -tv audioid=<input#>
37 * options which will not be implemented (probably sometime in future, if possible):
40 * * decimation=<1|2|4>
44 * * [volume|bass|treble|balance]
47 * - LifeView FlyTV Prime 34FM (SAA7134 based) with driver from Ivan Uskov
48 * Partially works with:
49 * - ATI 9200 VIVO based card
54 * * stream goes with 24.93 FPS (NTSC), while reporting 25 FPS (PAL) ?!
55 * * direct set frequency call does not work ('Insufficient Buffer' error)
56 * * audio stream goes with about 1 sample/sec rate when capturing sound from audio card
59 * * check audio with small buffer on vivo !!!
60 * * norm for IAMVideoDecoder and for IAMTVtuner - differs !!
61 * * check how to change TVFormat on VIVO card without tuner
62 * * Flip image upside-down for RGB formats.
64 * * remove debug sleep()
65 * * Add some notes to methods' parameters
66 * * refactor console messages
67 * * check using header files and keep only needed
68 * * add additional comments to methods' bodies
73 /// \ingroup tvi_dshow
78 #include "libmpcodecs/img_format.h"
79 #include "libmpcodecs/dec_teletext.h"
80 #include "libaf/af_format.h"
81 #include "osdep/timer.h"
86 #include "frequencies.h"
89 #include "tvi_dshow.h"
93 #define STDCALL __stdcall
96 static tvi_handle_t
*tvi_init_dshow(tv_param_t
* tv_param
);
99 *---------------------------------------------------------------------------------------
103 *---------------------------------------------------------------------------------------
106 information about this file
108 const tvi_info_t tvi_info_dshow
= {
112 "Vladimir Voroshilov",
113 "Very experimental!! Use with caution"
118 ringbuffer related info
121 CRITICAL_SECTION
*pMutex
; ///< pointer to critical section (mutex)
122 char **ringbuffer
; ///< ringbuffer array
123 double*dpts
; ///< samples' timestamps
125 int buffersize
; ///< size of buffer in blocks
126 int blocksize
; ///< size of individual block
127 int head
; ///< index of first valid sample
128 int tail
; ///< index of last valid sample
129 int count
; ///< count of valid samples in ringbuffer
130 double tStart
; ///< pts of first sample (first sample should have pts 0)
131 } grabber_ringbuffer_t
;
133 typedef enum { unknown
, video
, audio
, vbi
} stream_type
;
136 CSampleGrabberCD definition
138 typedef struct CSampleGrabberCB
{
139 ISampleGrabberCBVtbl
*lpVtbl
;
142 grabber_ringbuffer_t
*pbuf
;
146 Chain related structure
149 stream_type type
; ///< stream type
150 const GUID
* majortype
; ///< GUID of major mediatype (video/audio/vbi)
151 const GUID
* pin_category
; ///< pin category (pointer to one of PIN_CATEGORY_*)
153 IBaseFilter
*pCaptureFilter
; ///< capture device filter
154 IAMStreamConfig
*pStreamConfig
; ///< for configuring stream
155 ISampleGrabber
*pSG
; ///< ISampleGrabber interface of SampleGrabber filter
156 IBaseFilter
*pSGF
; ///< IBaseFilter interface of SampleGrabber filter
157 IPin
*pCapturePin
; ///< output capture pin
158 IPin
*pSGIn
; ///< input pin of SampleGrabber filter
160 grabber_ringbuffer_t
*rbuf
; ///< sample frabber data
161 CSampleGrabberCB
* pCSGCB
; ///< callback object
163 AM_MEDIA_TYPE
*pmt
; ///< stream properties.
164 int nFormatUsed
; ///< index of used format
165 AM_MEDIA_TYPE
**arpmt
; ///< available formats
166 void** arStreamCaps
; ///< VIDEO_STREAM_CONFIG_CAPS or AUDIO_STREAM_CONFIG_CAPS
169 typedef struct priv
{
170 int dev_index
; ///< capture device index in device list (defaul: 0, first available device)
171 int adev_index
; ///< audio capture device index in device list (default: -1, not used)
172 int immediate_mode
; ///< immediate mode (no sound capture)
173 int state
; ///< state: 1-filter graph running, 0-filter graph stopped
174 int direct_setfreq_call
; ///< 0-find nearest channels from system channel list(workaround),1-direct call to set frequency
175 int direct_getfreq_call
; ///< 0-find frequncy from frequency table (workaround),1-direct call to get frequency
177 int fcc
; ///< used video format code (FourCC)
178 int width
; ///< picture width (default: auto)
179 int height
; ///< picture height (default: auto)
181 int channels
; ///< number of audio channels (default: auto)
182 int samplerate
; ///< audio samplerate (default: auto)
184 long *freq_table
; ///< frequency table (in Hz)
185 int freq_table_len
; ///< length of freq table
186 int first_channel
; ///< channel number of first entry in freq table
187 int input
; ///< used input
189 chain_t
* chains
[3]; ///< chains' data (0-video, 1-audio, 2-vbi)
191 IAMTVTuner
*pTVTuner
; ///< interface for tuner device
192 IGraphBuilder
*pGraph
; ///< filter graph
193 ICaptureGraphBuilder2
*pBuilder
; ///< graph builder
194 IMediaControl
*pMediaControl
; ///< interface for controlling graph (start, stop,...)
195 IAMVideoProcAmp
*pVideoProcAmp
; ///< for adjusting hue,saturation,etc
196 IAMCrossbar
*pCrossbar
; ///< for selecting input (Tuner,Composite,S-Video,...)
197 DWORD dwRegister
; ///< allow graphedit to connect to our graph
198 void *priv_vbi
; ///< private VBI data structure
199 tt_stream_props tsp
; ///< data for VBI initialization
201 tv_param_t
* tv_param
; ///< TV parameters
207 country table entry structure (for loading freq table stored in kstvtuner.ax
210 structure have to be 2-byte aligned and have 10-byte length!!
212 typedef struct __attribute__((__packed__
)) {
213 WORD CountryCode
; ///< Country code
214 WORD CableFreqTable
; ///< index of resource with frequencies for cable channels
215 WORD BroadcastFreqTable
; ///< index of resource with frequencies for broadcast channels
216 DWORD VideoStandard
; ///< used video standard
219 information about image formats
222 uint32_t fmt
; ///< FourCC
223 const GUID
*subtype
; ///< DirectShow's subtype
224 int nBits
; ///< number of bits
225 int nCompression
; ///< complression
226 int tail
; ///< number of additional bytes followed VIDEOINFOHEADER structure
230 *---------------------------------------------------------------------------------------
232 * Methods forward declaration
234 *---------------------------------------------------------------------------------------
236 static HRESULT
init_ringbuffer(grabber_ringbuffer_t
* rb
, int buffersize
,
238 static HRESULT
show_filter_info(IBaseFilter
* pFilter
);
240 //defined in current MinGW release
241 HRESULT STDCALL
GetRunningObjectTable(DWORD
, IRunningObjectTable
**);
242 HRESULT STDCALL
CreateItemMoniker(LPCOLESTR
, LPCOLESTR
, IMoniker
**);
244 static CSampleGrabberCB
*CSampleGrabberCB_Create(grabber_ringbuffer_t
*
246 static int set_crossbar_input(priv_t
* priv
, int input
);
247 static int subtype2imgfmt(const GUID
* subtype
);
250 *---------------------------------------------------------------------------------------
252 * Global constants and variables
254 *---------------------------------------------------------------------------------------
257 lookup tables for physical connector types
259 static const struct {
262 } tv_physcon_types
[]={
263 {PhysConn_Video_Tuner
, "Tuner" },
264 {PhysConn_Video_Composite
, "Composite" },
265 {PhysConn_Video_SVideo
, "S-Video" },
266 {PhysConn_Video_RGB
, "RGB" },
267 {PhysConn_Video_YRYBY
, "YRYBY" },
268 {PhysConn_Video_SerialDigital
, "SerialDigital" },
269 {PhysConn_Video_ParallelDigital
, "ParallelDigital"},
270 {PhysConn_Video_VideoDecoder
, "VideoDecoder" },
271 {PhysConn_Video_VideoEncoder
, "VideoEncoder" },
272 {PhysConn_Video_SCART
, "SCART" },
273 {PhysConn_Video_Black
, "Blaack" },
274 {PhysConn_Audio_Tuner
, "Tuner" },
275 {PhysConn_Audio_Line
, "Line" },
276 {PhysConn_Audio_Mic
, "Mic" },
277 {PhysConn_Audio_AESDigital
, "AESDiital" },
278 {PhysConn_Audio_SPDIFDigital
, "SPDIFDigital" },
279 {PhysConn_Audio_AudioDecoder
, "AudioDecoder" },
280 {PhysConn_Audio_SCSI
, "SCSI" },
281 {PhysConn_Video_SCSI
, "SCSI" },
282 {PhysConn_Audio_AUX
, "AUX" },
283 {PhysConn_Video_AUX
, "AUX" },
284 {PhysConn_Audio_1394
, "1394" },
285 {PhysConn_Video_1394
, "1394" },
286 {PhysConn_Audio_USB
, "USB" },
287 {PhysConn_Video_USB
, "USB" },
291 static const struct {
294 } tv_chanlist2country
[]={
306 //directshow table uses eastern europe freq table for russia
308 //directshow table uses western europe freq table for germany
319 array, contains information about various supported (i hope) image formats
321 static const img_fmt img_fmt_list
[] = {
322 {IMGFMT_YUY2
, &MEDIASUBTYPE_YUY2
, 16, IMGFMT_YUY2
, 0},
323 {IMGFMT_YV12
, &MEDIASUBTYPE_YV12
, 12, IMGFMT_YV12
, 0},
324 {IMGFMT_IYUV
, &MEDIASUBTYPE_IYUV
, 12, IMGFMT_IYUV
, 0},
325 {IMGFMT_I420
, &MEDIASUBTYPE_I420
, 12, IMGFMT_I420
, 0},
326 {IMGFMT_UYVY
, &MEDIASUBTYPE_UYVY
, 16, IMGFMT_UYVY
, 0},
327 {IMGFMT_YVYU
, &MEDIASUBTYPE_YVYU
, 16, IMGFMT_YVYU
, 0},
328 {IMGFMT_YVU9
, &MEDIASUBTYPE_YVU9
, 9, IMGFMT_YVU9
, 0},
329 {IMGFMT_BGR32
, &MEDIASUBTYPE_RGB32
, 32, 0, 0},
330 {IMGFMT_BGR24
, &MEDIASUBTYPE_RGB24
, 24, 0, 0},
331 {IMGFMT_BGR16
, &MEDIASUBTYPE_RGB565
, 16, 3, 12},
332 {IMGFMT_BGR15
, &MEDIASUBTYPE_RGB555
, 16, 3, 12},
333 {0, &GUID_NULL
, 0, 0, 0}
336 #define TV_NORMS_COUNT 19
337 static const struct {
340 } tv_norms
[TV_NORMS_COUNT
] = {
342 AnalogVideo_NTSC_M
, "ntsc-m"}, {
343 AnalogVideo_NTSC_M_J
, "ntsc-mj"}, {
344 AnalogVideo_NTSC_433
, "ntsc-433"}, {
345 AnalogVideo_PAL_B
, "pal-b"}, {
346 AnalogVideo_PAL_D
, "pal-d"}, {
347 AnalogVideo_PAL_G
, "pal-g"}, {
348 AnalogVideo_PAL_H
, "pal-h"}, {
349 AnalogVideo_PAL_I
, "pal-i"}, {
350 AnalogVideo_PAL_M
, "pal-m"}, {
351 AnalogVideo_PAL_N
, "pal-n"}, {
352 AnalogVideo_PAL_60
, "pal-60"}, {
353 AnalogVideo_SECAM_B
, "secam-b"}, {
354 AnalogVideo_SECAM_D
, "secam-d"}, {
355 AnalogVideo_SECAM_G
, "secam-g"}, {
356 AnalogVideo_SECAM_H
, "secam-h"}, {
357 AnalogVideo_SECAM_K
, "secam-k"}, {
358 AnalogVideo_SECAM_K1
, "secam-k1"}, {
359 AnalogVideo_SECAM_L
, "secam-l"}, {
360 AnalogVideo_SECAM_L1
, "secam-l1"}
362 static long tv_available_norms
[TV_NORMS_COUNT
];
363 static int tv_available_norms_count
= 0;
366 static long *tv_available_inputs
;
367 static int tv_available_inputs_count
= 0;
370 *---------------------------------------------------------------------------------------
372 * Various GUID definitions
374 *---------------------------------------------------------------------------------------
376 // selectany can not be used with "static", fixes compilation with mingw-w64
377 #undef DECLSPEC_SELECTANY
378 #define DECLSPEC_SELECTANY
379 /// CLSID definitions (used for CoCreateInstance call)
380 #define CLSID_SampleGrabber MP_CLSID_SampleGrabber
381 static DEFINE_GUID(CLSID_SampleGrabber
, 0xC1F400A0, 0x3F08, 0x11d3, 0x9F, 0x0B,
382 0x00, 0x60, 0x08, 0x03, 0x9E, 0x37);
383 #define CLSID_NullRenderer MP_CLSID_NullRenderer
384 static DEFINE_GUID(CLSID_NullRenderer
, 0xC1F400A4, 0x3F08, 0x11d3, 0x9F, 0x0B,
385 0x00, 0x60, 0x08, 0x03, 0x9E, 0x37);
386 #define CLSID_SystemDeviceEnum MP_CLSID_SystemDeviceEnum
387 static DEFINE_GUID(CLSID_SystemDeviceEnum
, 0x62BE5D10, 0x60EB, 0x11d0, 0xBD, 0x3B,
388 0x00, 0xA0, 0xC9, 0x11, 0xCE, 0x86);
389 #define CLSID_CaptureGraphBuilder2 MP_CLSID_CaptureGraphBuilder2
390 static DEFINE_GUID(CLSID_CaptureGraphBuilder2
, 0xBF87B6E1, 0x8C27, 0x11d0, 0xB3,
391 0xF0, 0x00, 0xAA, 0x00, 0x37, 0x61, 0xC5);
392 #define CLSID_VideoInputDeviceCategory MP_CLSID_VideoInputDeviceCategory
393 static DEFINE_GUID(CLSID_VideoInputDeviceCategory
, 0x860BB310, 0x5D01, 0x11d0,
394 0xBD, 0x3B, 0x00, 0xA0, 0xC9, 0x11, 0xCE, 0x86);
395 #define CLSID_AudioInputDeviceCategory MP_CLSID_AudioInputDeviceCategory
396 static DEFINE_GUID(CLSID_AudioInputDeviceCategory
, 0x33d9a762, 0x90c8, 0x11d0,
397 0xbd, 0x43, 0x00, 0xa0, 0xc9, 0x11, 0xce, 0x86);
398 #define CLSID_FilterGraph MP_CLSID_FilterGraph
399 static DEFINE_GUID(CLSID_FilterGraph
, 0xe436ebb3, 0x524f, 0x11ce, 0x9f, 0x53,
400 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70);
401 #define CLSID_SystemClock MP_CLSID_SystemClock
402 static DEFINE_GUID(CLSID_SystemClock
, 0xe436ebb1, 0x524f, 0x11ce, 0x9f, 0x53,
403 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70);
405 #define CLSID_CaptureGraphBuilder MP_CLSID_CaptureGraphBuilder
406 static DEFINE_GUID(CLSID_CaptureGraphBuilder
, 0xBF87B6E0, 0x8C27, 0x11d0, 0xB3,
407 0xF0, 0x00, 0xAA, 0x00, 0x37, 0x61, 0xC5);
408 #define CLSID_VideoPortManager MP_CLSID_VideoPortManager
409 static DEFINE_GUID(CLSID_VideoPortManager
, 0x6f26a6cd, 0x967b, 0x47fd, 0x87, 0x4a,
410 0x7a, 0xed, 0x2c, 0x9d, 0x25, 0xa2);
411 #define IID_IPin MP_IID_IPin
412 static DEFINE_GUID(IID_IPin
, 0x56a86891, 0x0ad4, 0x11ce, 0xb0, 0x3a, 0x00, 0x20,
413 0xaf, 0x0b, 0xa7, 0x70);
414 #define IID_ICaptureGraphBuilder MP_IID_ICaptureGraphBuilder
415 static DEFINE_GUID(IID_ICaptureGraphBuilder
, 0xbf87b6e0, 0x8c27, 0x11d0, 0xb3,
416 0xf0, 0x00, 0xaa, 0x00, 0x37, 0x61, 0xc5);
417 #define IID_IFilterGraph MP_IID_IFilterGraph
418 static DEFINE_GUID(IID_IFilterGraph
, 0x56a8689f, 0x0ad4, 0x11ce, 0xb0, 0x3a, 0x00,
419 0x20, 0xaf, 0x0b, 0xa7, 0x70);
420 #define PIN_CATEGORY_PREVIEW MP_PIN_CATEGORY_PREVIEW
421 static DEFINE_GUID(PIN_CATEGORY_PREVIEW
, 0xfb6c4282, 0x0353, 0x11d1, 0x90, 0x5f,
422 0x00, 0x00, 0xc0, 0xcc, 0x16, 0xba);
425 /// IID definitions (used for QueryInterface call)
426 #define IID_IReferenceClock MP_IID_IReferenceClock
427 static DEFINE_GUID(IID_IReferenceClock
, 0x56a86897, 0x0ad4, 0x11ce, 0xb0, 0x3a,
428 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70);
429 #define IID_IAMBufferNegotiation MP_IID_IAMBufferNegotiation
430 static DEFINE_GUID(IID_IAMBufferNegotiation
, 0x56ED71A0, 0xAF5F, 0x11D0, 0xB3, 0xF0,
431 0x00, 0xAA, 0x00, 0x37, 0x61, 0xC5);
432 #define IID_IKsPropertySet MP_IID_IKsPropertySet
433 static DEFINE_GUID(IID_IKsPropertySet
, 0x31efac30, 0x515c, 0x11d0, 0xa9, 0xaa,
434 0x00, 0xaa, 0x00, 0x61, 0xbe, 0x93);
435 #define IID_ISampleGrabber MP_IID_ISampleGrabber
436 static DEFINE_GUID(IID_ISampleGrabber
, 0x6B652FFF, 0x11FE, 0x4fce, 0x92, 0xAD,
437 0x02, 0x66, 0xB5, 0xD7, 0xC7, 0x8F);
438 #define IID_ISampleGrabberCB MP_IID_ISampleGrabberCB
439 static DEFINE_GUID(IID_ISampleGrabberCB
, 0x0579154A, 0x2B53, 0x4994, 0xB0, 0xD0,
440 0xE7, 0x73, 0x14, 0x8E, 0xFF, 0x85);
441 #define IID_ICaptureGraphBuilder2 MP_IID_ICaptureGraphBuilder2
442 static DEFINE_GUID(IID_ICaptureGraphBuilder2
, 0x93e5a4e0, 0x2d50, 0x11d2, 0xab,
443 0xfa, 0x00, 0xa0, 0xc9, 0xc6, 0xe3, 0x8d);
444 #define IID_ICreateDevEnum MP_IID_ICreateDevEnum
445 static DEFINE_GUID(IID_ICreateDevEnum
, 0x29840822, 0x5b84, 0x11d0, 0xbd, 0x3b,
446 0x00, 0xa0, 0xc9, 0x11, 0xce, 0x86);
447 #define IID_IGraphBuilder MP_IID_IGraphBuilder
448 static DEFINE_GUID(IID_IGraphBuilder
, 0x56a868a9, 0x0ad4, 0x11ce, 0xb0, 0x3a,
449 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70);
450 #define IID_IAMVideoProcAmp MP_IID_IAMVideoProcAmp
451 static DEFINE_GUID(IID_IAMVideoProcAmp
, 0xC6E13360, 0x30AC, 0x11d0, 0xA1, 0x8C,
452 0x00, 0xA0, 0xC9, 0x11, 0x89, 0x56);
453 #define IID_IVideoWindow MP_IID_IVideoWindow
454 static DEFINE_GUID(IID_IVideoWindow
, 0x56a868b4, 0x0ad4, 0x11ce, 0xb0, 0x3a, 0x00,
455 0x20, 0xaf, 0x0b, 0xa7, 0x70);
456 #define IID_IMediaControl MP_IID_IMediaControl
457 static DEFINE_GUID(IID_IMediaControl
, 0x56a868b1, 0x0ad4, 0x11ce, 0xb0, 0x3a,
458 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70);
459 #define IID_IAMTVTuner MP_IID_IAMTVTuner
460 static DEFINE_GUID(IID_IAMTVTuner
, 0x211A8766, 0x03AC, 0x11d1, 0x8D, 0x13, 0x00,
461 0xAA, 0x00, 0xBD, 0x83, 0x39);
462 #define IID_IAMCrossbar MP_IID_IAMCrossbar
463 static DEFINE_GUID(IID_IAMCrossbar
, 0xc6e13380, 0x30ac, 0x11d0, 0xa1, 0x8c, 0x00,
464 0xa0, 0xc9, 0x11, 0x89, 0x56);
465 #define IID_IAMStreamConfig MP_IID_IAMStreamConfig
466 static DEFINE_GUID(IID_IAMStreamConfig
, 0xc6e13340, 0x30ac, 0x11d0, 0xa1, 0x8c,
467 0x00, 0xa0, 0xc9, 0x11, 0x89, 0x56);
468 #define IID_IAMAudioInputMixer MP_IID_IAMAudioInputMixer
469 static DEFINE_GUID(IID_IAMAudioInputMixer
, 0x54C39221, 0x8380, 0x11d0, 0xB3, 0xF0,
470 0x00, 0xAA, 0x00, 0x37, 0x61, 0xC5);
471 #define IID_IAMTVAudio MP_IID_IAMTVAudio
472 static DEFINE_GUID(IID_IAMTVAudio
, 0x83EC1C30, 0x23D1, 0x11d1, 0x99, 0xE6, 0x00,
473 0xA0, 0xC9, 0x56, 0x02, 0x66);
474 #define IID_IAMAnalogVideoDecoder MP_IID_IAMAnalogVideoDecoder
475 static DEFINE_GUID(IID_IAMAnalogVideoDecoder
, 0xC6E13350, 0x30AC, 0x11d0, 0xA1,
476 0x8C, 0x00, 0xA0, 0xC9, 0x11, 0x89, 0x56);
477 #define IID_IPropertyBag MP_IID_IPropertyBag
478 static DEFINE_GUID(IID_IPropertyBag
, 0x55272a00, 0x42cb, 0x11ce, 0x81, 0x35, 0x00,
479 0xaa, 0x00, 0x4b, 0xb8, 0x51);
480 #define PIN_CATEGORY_CAPTURE MP_PIN_CATEGORY_CAPTURE
481 static DEFINE_GUID(PIN_CATEGORY_CAPTURE
, 0xfb6c4281, 0x0353, 0x11d1, 0x90, 0x5f,
482 0x00, 0x00, 0xc0, 0xcc, 0x16, 0xba);
483 #define PIN_CATEGORY_VIDEOPORT MP_PIN_CATEGORY_VIDEOPORT
484 static DEFINE_GUID(PIN_CATEGORY_VIDEOPORT
, 0xfb6c4285, 0x0353, 0x11d1, 0x90, 0x5f,
485 0x00, 0x00, 0xc0, 0xcc, 0x16, 0xba);
486 #define PIN_CATEGORY_PREVIEW MP_PIN_CATEGORY_PREVIEW
487 static DEFINE_GUID(PIN_CATEGORY_PREVIEW
, 0xfb6c4282, 0x0353, 0x11d1, 0x90, 0x5f,
488 0x00, 0x00, 0xc0, 0xcc, 0x16, 0xba);
489 #define PIN_CATEGORY_VBI MP_PIN_CATEGORY_VBI
490 static DEFINE_GUID(PIN_CATEGORY_VBI
, 0xfb6c4284, 0x0353, 0x11d1, 0x90, 0x5f,
491 0x00, 0x00, 0xc0, 0xcc, 0x16, 0xba);
492 #define PROPSETID_TUNER MP_PROPSETID_TUNER
493 static DEFINE_GUID(PROPSETID_TUNER
, 0x6a2e0605, 0x28e4, 0x11d0, 0xa1, 0x8c, 0x00,
494 0xa0, 0xc9, 0x11, 0x89, 0x56);
495 #define MEDIATYPE_VBI MP_MEDIATYPE_VBI
496 static DEFINE_GUID(MEDIATYPE_VBI
, 0xf72a76e1, 0xeb0a, 0x11d0, 0xac, 0xe4, 0x00,
497 0x00, 0xc0, 0xcc, 0x16, 0xba);
499 #define INSTANCEDATA_OF_PROPERTY_PTR(x) (((KSPROPERTY*)(x)) + 1)
500 #define INSTANCEDATA_OF_PROPERTY_SIZE(x) (sizeof((x)) - sizeof(KSPROPERTY))
502 #define DEVICE_NAME_MAX_LEN 2000
504 /*---------------------------------------------------------------------------------------
505 * Methods, called only from this file
506 *---------------------------------------------------------------------------------------*/
508 void set_buffer_preference(int nDiv
,WAVEFORMATEX
* pWF
,IPin
* pOutPin
,IPin
* pInPin
){
509 ALLOCATOR_PROPERTIES prop
;
510 IAMBufferNegotiation
* pBN
;
514 prop
.cbBuffer
= pWF
->nAvgBytesPerSec
/nDiv
;
517 prop
.cbBuffer
+= pWF
->nBlockAlign
- 1;
518 prop
.cbBuffer
-= prop
.cbBuffer
% pWF
->nBlockAlign
;
522 hr
=OLE_QUERYINTERFACE(pOutPin
,IID_IAMBufferNegotiation
,pBN
);
524 mp_msg(MSGT_TV
,MSGL_DBG2
,"tvi_dshow: pOutPin->QueryInterface(IID_IAMBufferNegotiation) Error: 0x%x\n",(unsigned int)hr
);
526 hr
=OLE_CALL_ARGS(pBN
,SuggestAllocatorProperties
,&prop
);
528 mp_msg(MSGT_TV
,MSGL_DBG2
,"tvi_dshow:pOutPin->SuggestAllocatorProperties Error:0x%x\n",(unsigned int)hr
);
529 OLE_RELEASE_SAFE(pBN
);
531 hr
=OLE_QUERYINTERFACE(pInPin
,IID_IAMBufferNegotiation
,pBN
);
533 mp_msg(MSGT_TV
,MSGL_DBG2
,"tvi_dshow: pInPin->QueryInterface(IID_IAMBufferNegotiation) Error: 0x%x",(unsigned int)hr
);
535 hr
=OLE_CALL_ARGS(pBN
,SuggestAllocatorProperties
,&prop
);
537 mp_msg(MSGT_TV
,MSGL_DBG2
,"tvi_dshow: pInPit->SuggestAllocatorProperties Error:0x%x\n",(unsigned int)hr
);
538 OLE_RELEASE_SAFE(pBN
);
542 *---------------------------------------------------------------------------------------
544 * CSampleGrabberCD class. Used for receiving samples from DirectShow.
546 *---------------------------------------------------------------------------------------
548 /// CSampleGrabberCD destructor
549 static void CSampleGrabberCB_Destroy(CSampleGrabberCB
* This
)
555 /// CSampleGrabberCD IUnknown interface methods implementation
556 static long STDCALL
CSampleGrabberCB_QueryInterface(ISampleGrabberCB
*
561 CSampleGrabberCB
*me
= (CSampleGrabberCB
*) This
;
564 Debug
printf("CSampleGrabberCB_QueryInterface(%p) called\n", This
);
567 for (r
= me
->interfaces
;
568 i
< sizeof(me
->interfaces
) / sizeof(me
->interfaces
[0]); r
++, i
++)
569 if (!memcmp(r
, riid
, sizeof(*r
))) {
570 OLE_CALL(This
, AddRef
);
574 Debug
printf("Query failed! (GUID: 0x%x)\n", *(unsigned int *) riid
);
575 return E_NOINTERFACE
;
578 static long STDCALL
CSampleGrabberCB_AddRef(ISampleGrabberCB
* This
)
580 CSampleGrabberCB
*me
= (CSampleGrabberCB
*) This
;
581 Debug
printf("CSampleGrabberCB_AddRef(%p) called (ref:%d)\n", This
,
583 return ++(me
->refcount
);
586 static long STDCALL
CSampleGrabberCB_Release(ISampleGrabberCB
* This
)
588 CSampleGrabberCB
*me
= (CSampleGrabberCB
*) This
;
589 Debug
printf("CSampleGrabberCB_Release(%p) called (new ref:%d)\n",
590 This
, me
->refcount
- 1);
591 if (--(me
->refcount
) == 0)
592 CSampleGrabberCB_Destroy(me
);
597 HRESULT STDCALL
CSampleGrabberCB_BufferCB(ISampleGrabberCB
* This
,
599 BYTE
* pBuffer
, long lBufferLen
)
601 CSampleGrabberCB
*this = (CSampleGrabberCB
*) This
;
602 grabber_ringbuffer_t
*rb
= this->pbuf
;
607 if (!rb
->ringbuffer
) {
608 rb
->buffersize
/= lBufferLen
;
609 if (init_ringbuffer(rb
, rb
->buffersize
, lBufferLen
) != S_OK
)
612 mp_msg(MSGT_TV
, MSGL_DBG4
,
613 "tvi_dshow: BufferCB(%p): len=%ld ts=%f\n", This
, lBufferLen
, SampleTime
);
614 EnterCriticalSection(rb
->pMutex
);
615 if (rb
->count
>= rb
->buffersize
) {
616 rb
->head
= (rb
->head
+ 1) % rb
->buffersize
;
620 memcpy(rb
->ringbuffer
[rb
->tail
], pBuffer
,
621 lBufferLen
< rb
->blocksize
? lBufferLen
: rb
->blocksize
);
622 rb
->dpts
[rb
->tail
] = SampleTime
;
623 rb
->tail
= (rb
->tail
+ 1) % rb
->buffersize
;
625 LeaveCriticalSection(rb
->pMutex
);
630 /// wrapper. directshow does the same when BufferCB callback is requested
631 HRESULT STDCALL
CSampleGrabberCB_SampleCB(ISampleGrabberCB
* This
,
633 LPMEDIASAMPLE pSample
)
637 long long tStart
,tEnd
;
639 grabber_ringbuffer_t
*rb
= ((CSampleGrabberCB
*)This
)->pbuf
;
641 len
=OLE_CALL(pSample
,GetSize
);
643 hr
=OLE_CALL_ARGS(pSample
,GetTime
,&tStart
,&tEnd
);
647 mp_msg(MSGT_TV
, MSGL_DBG4
,"tvi_dshow: SampleCB(%p): %d/%d %f\n", This
,rb
->count
,rb
->buffersize
,1e-7*tStart
);
648 hr
=OLE_CALL_ARGS(pSample
,GetPointer
,(void*)&buf
);
652 hr
=CSampleGrabberCB_BufferCB(This
,1e-7*tStart
,buf
,len
);
657 /// main grabbing routine
658 static CSampleGrabberCB
*CSampleGrabberCB_Create(grabber_ringbuffer_t
*
661 CSampleGrabberCB
*This
= malloc(sizeof(CSampleGrabberCB
));
665 This
->lpVtbl
= malloc(sizeof(ISampleGrabberVtbl
));
667 CSampleGrabberCB_Destroy(This
);
671 This
->lpVtbl
->QueryInterface
= CSampleGrabberCB_QueryInterface
;
672 This
->lpVtbl
->AddRef
= CSampleGrabberCB_AddRef
;
673 This
->lpVtbl
->Release
= CSampleGrabberCB_Release
;
674 This
->lpVtbl
->SampleCB
= CSampleGrabberCB_SampleCB
;
675 This
->lpVtbl
->BufferCB
= CSampleGrabberCB_BufferCB
;
677 This
->interfaces
[0] = IID_IUnknown
;
678 This
->interfaces
[1] = IID_ISampleGrabberCB
;
686 *---------------------------------------------------------------------------------------
688 * ROT related methods (register, unregister)
690 *---------------------------------------------------------------------------------------
693 Registering graph in ROT. User will be able to connect to graph from GraphEdit.
695 static HRESULT
AddToRot(IUnknown
* pUnkGraph
, DWORD
* pdwRegister
)
698 IRunningObjectTable
*pROT
;
702 if (FAILED(GetRunningObjectTable(0, &pROT
))) {
705 wsprintfW(wsz
, L
"FilterGraph %08x pid %08x", (DWORD_PTR
) pUnkGraph
,
706 GetCurrentProcessId());
707 hr
= CreateItemMoniker(L
"!", wsz
, &pMoniker
);
709 hr
= OLE_CALL_ARGS(pROT
, Register
, ROTFLAGS_REGISTRATIONKEEPSALIVE
,
710 pUnkGraph
, pMoniker
, pdwRegister
);
711 OLE_RELEASE_SAFE(pMoniker
);
713 OLE_RELEASE_SAFE(pROT
);
717 /// Unregistering graph in ROT
718 static void RemoveFromRot(DWORD dwRegister
)
720 IRunningObjectTable
*pROT
;
721 if (SUCCEEDED(GetRunningObjectTable(0, &pROT
))) {
722 OLE_CALL_ARGS(pROT
, Revoke
, dwRegister
);
723 OLE_RELEASE_SAFE(pROT
);
728 *---------------------------------------------------------------------------------------
730 * ringbuffer related methods (init, destroy)
732 *---------------------------------------------------------------------------------------
735 * \brief ringbuffer destroying routine
737 * \param rb pointer to empty (just allocated) ringbuffer structure
739 * \note routine does not frees memory, allocated for grabber_rinbuffer_s structure
741 static void destroy_ringbuffer(grabber_ringbuffer_t
* rb
)
748 if (rb
->ringbuffer
) {
749 for (i
= 0; i
< rb
->buffersize
; i
++)
750 free(rb
->ringbuffer
[i
]);
751 free(rb
->ringbuffer
);
752 rb
->ringbuffer
= NULL
;
757 DeleteCriticalSection(rb
->pMutex
);
770 * \brief ringbuffer initialization
772 * \param rb pointer to empty (just allocated) ringbuffer structure
773 * \param buffersize size of buffer in blocks
774 * \param blocksize size of buffer's block
776 * \return S_OK if success
777 * \return E_OUTOFMEMORY not enough memory
779 * \note routine does not allocates memory for grabber_rinbuffer_s structure
781 static HRESULT
init_ringbuffer(grabber_ringbuffer_t
* rb
, int buffersize
,
787 return E_OUTOFMEMORY
;
789 rb
->buffersize
= buffersize
< 2 ? 2 : buffersize
;
790 rb
->blocksize
= blocksize
;
792 mp_msg(MSGT_TV
, MSGL_DBG2
, "tvi_dshow: Capture buffer: %d blocks of %d bytes.\n",
793 rb
->buffersize
, rb
->blocksize
);
795 rb
->ringbuffer
= malloc(rb
->buffersize
* sizeof(char *));
798 memset(rb
->ringbuffer
, 0, rb
->buffersize
* sizeof(char *));
800 for (i
= 0; i
< rb
->buffersize
; i
++) {
801 rb
->ringbuffer
[i
] = malloc(rb
->blocksize
* sizeof(char));
802 if (!rb
->ringbuffer
[i
]) {
803 destroy_ringbuffer(rb
);
804 return E_OUTOFMEMORY
;
807 rb
->dpts
= malloc(rb
->buffersize
* sizeof(double));
809 destroy_ringbuffer(rb
);
810 return E_OUTOFMEMORY
;
816 rb
->pMutex
= malloc(sizeof(CRITICAL_SECTION
));
818 destroy_ringbuffer(rb
);
819 return E_OUTOFMEMORY
;
821 InitializeCriticalSection(rb
->pMutex
);
826 *---------------------------------------------------------------------------------------
828 * Tuner related methods (frequency, capabilities, etc
830 *---------------------------------------------------------------------------------------
833 * \brief returns string with name for givend PsysCon_* constant
835 * \param lPhysicalType constant from PhysicalConnectorType enumeration
837 * \return pointer to string with apropriate name
840 * Caller should not free returned pointer
842 static char *physcon2str(const long lPhysicalType
)
845 for(i
=0; tv_physcon_types
[i
].name
; i
++)
846 if(tv_physcon_types
[i
].type
==lPhysicalType
)
847 return tv_physcon_types
[i
].name
;
852 * \brief converts MPlayer's chanlist to system country code.
854 * \param chanlist MPlayer's chanlist name
856 * \return system country code
859 * After call to IAMTVTuner::put_CountryCode with returned value tuner switches to frequency table used in specified
860 * country (which is usually larger then MPlayer's one, so workaround will work fine).
863 * Resolve trouble with cable channels (DirectShow's tuners must be switched between broadcast and cable channels modes.
865 static int chanlist2country(char *chanlist
)
868 for(i
=0; tv_chanlist2country
[i
].chanlist_name
; i
++)
869 if (!strcmp(chanlist
, tv_chanlist2country
[i
].chanlist_name
))
871 return tv_chanlist2country
[i
].country_code
;
875 * \brief loads specified resource from module and return pointer to it
877 * \param hDLL valid module desriptor
878 * \param index index of resource. resource with name "#<index>" will be loaded
880 * \return pointer to loader resource or NULL if error occured
882 static void *GetRC(HMODULE hDLL
, int index
)
889 snprintf(szRCDATA
, 10, "#%d", (int)RT_RCDATA
);
890 snprintf(szName
, 10, "#%d", index
);
892 hRes
= FindResource(hDLL
, szName
, szRCDATA
);
896 hTable
= LoadResource(hDLL
, hRes
);
900 return LockResource(hTable
);
904 * \brief loads frequency table for given country from kstvtune.ax
906 * \param[in] nCountry - country code
907 * \param[in] nInputType (TunerInputCable or TunerInputAntenna)
908 * \param[out] pplFreqTable - address of variable that receives pointer to array, containing frequencies
909 * \param[out] pnLen length of array
910 * \param[out] pnFirst - channel number of first entry in array (nChannelMax)
912 * \return S_OK if success
913 * \return E_POINTER pplFreqTable==NULL || plFirst==NULL || pnLen==NULL
914 * \return E_FAIL error occured during load
917 * - array must be freed by caller
918 * - MSDN says that it is not neccessery to unlock or free resource. It will be done after unloading DLL
920 static HRESULT
load_freq_table(int nCountry
, int nInputType
,
921 long **pplFreqTable
, int *pnLen
,
926 TRCCountryList
*pCountryList
;
929 mp_msg(MSGT_TV
, MSGL_DBG4
, "tvi_dshow: load_freq_table called %d (%s)\n",nCountry
,nInputType
== TunerInputAntenna
? "broadcast" : "cable");
930 /* ASSERT(sizeof(TRCCountryList)==10); // need properly aligned structure */
932 if (!pplFreqTable
|| !pnFirst
|| !pnLen
)
937 hDLL
= LoadLibrary("kstvtune.ax");
941 pCountryList
= GetRC(hDLL
, 9999);
946 for (i
= 0; pCountryList
[i
].CountryCode
!= 0; i
++)
947 if (pCountryList
[i
].CountryCode
== nCountry
)
949 if (pCountryList
[i
].CountryCode
== 0) {
953 if (nInputType
== TunerInputCable
)
954 index
= pCountryList
[i
].CableFreqTable
;
956 index
= pCountryList
[i
].BroadcastFreqTable
;
958 plFreqTable
= GetRC(hDLL
, index
); //First element is number of first channel, second - number of last channel
963 *pnFirst
= plFreqTable
[0];
964 *pnLen
= (int) (plFreqTable
[1] - plFreqTable
[0] + 1);
965 *pplFreqTable
= malloc((*pnLen
) * sizeof(long));
966 if (!*pplFreqTable
) {
970 for (i
= 0; i
< *pnLen
; i
++) {
971 (*pplFreqTable
)[i
] = plFreqTable
[i
+ 2];
972 mp_msg(MSGT_TV
, MSGL_DBG4
, "tvi_dshow: load_freq_table #%d => (%ld)\n",i
+*pnFirst
,(*pplFreqTable
)[i
]);
979 * \brief tunes to given frequency through IKsPropertySet call
981 * \param pTVTuner IAMTVTuner interface of capture device
982 * \param lFreq frequency to tune (in Hz)
984 * \return S_OK success
985 * \return apropriate error code otherwise
988 * Due to either bug in driver or error in following code calll to IKsProperty::Set
989 * in this methods always fail with error 0x8007007a.
991 * \todo test code on other machines and an error
993 static HRESULT
set_frequency_direct(IAMTVTuner
* pTVTuner
, long lFreq
)
996 DWORD dwSupported
= 0;
998 KSPROPERTY_TUNER_MODE_CAPS_S mode_caps
;
999 KSPROPERTY_TUNER_FREQUENCY_S frequency
;
1000 IKsPropertySet
*pKSProp
;
1002 mp_msg(MSGT_TV
, MSGL_DBG4
, "tvi_dshow: set_frequency_direct called\n");
1004 memset(&mode_caps
, 0, sizeof(mode_caps
));
1005 memset(&frequency
, 0, sizeof(frequency
));
1007 hr
= OLE_QUERYINTERFACE(pTVTuner
, IID_IKsPropertySet
, pKSProp
);
1009 return hr
; //no IKsPropertySet interface
1011 mode_caps
.Mode
= AMTUNER_MODE_TV
;
1012 hr
= OLE_CALL_ARGS(pKSProp
, QuerySupported
, &PROPSETID_TUNER
,
1013 KSPROPERTY_TUNER_MODE_CAPS
, &dwSupported
);
1015 OLE_RELEASE_SAFE(pKSProp
);
1019 if (!dwSupported
& KSPROPERTY_SUPPORT_GET
) {
1020 OLE_RELEASE_SAFE(pKSProp
);
1021 return E_FAIL
; //PROPSETID_TINER not supported
1024 hr
= OLE_CALL_ARGS(pKSProp
, Get
, &PROPSETID_TUNER
,
1025 KSPROPERTY_TUNER_MODE_CAPS
,
1026 INSTANCEDATA_OF_PROPERTY_PTR(&mode_caps
),
1027 INSTANCEDATA_OF_PROPERTY_SIZE(mode_caps
),
1028 &mode_caps
, sizeof(mode_caps
), &cbBytes
);
1030 frequency
.Frequency
= lFreq
;
1032 if (mode_caps
.Strategy
== KS_TUNER_STRATEGY_DRIVER_TUNES
)
1033 frequency
.TuningFlags
= KS_TUNER_TUNING_FINE
;
1035 frequency
.TuningFlags
= KS_TUNER_TUNING_EXACT
;
1037 if (lFreq
< mode_caps
.MinFrequency
|| lFreq
> mode_caps
.MaxFrequency
) {
1038 OLE_RELEASE_SAFE(pKSProp
);
1042 hr
= OLE_CALL_ARGS(pKSProp
, Set
, &PROPSETID_TUNER
,
1043 KSPROPERTY_TUNER_FREQUENCY
,
1044 INSTANCEDATA_OF_PROPERTY_PTR(&frequency
),
1045 INSTANCEDATA_OF_PROPERTY_SIZE(frequency
),
1046 &frequency
, sizeof(frequency
));
1048 OLE_RELEASE_SAFE(pKSProp
);
1052 OLE_RELEASE_SAFE(pKSProp
);
1058 * \brief find channel with nearest frequency and set it
1060 * \param priv driver's private data
1061 * \param lFreq frequency in Hz
1063 * \return S_OK if success
1064 * \return E_FAIL if error occured
1066 static HRESULT
set_nearest_freq(priv_t
* priv
, long lFreq
)
1072 TunerInputType tunerInput
;
1075 mp_msg(MSGT_TV
, MSGL_DBG4
, "tvi_dshow: set_nearest_freq called: %ld\n", lFreq
);
1076 if(priv
->freq_table_len
== -1 && !priv
->freq_table
) {
1078 hr
= OLE_CALL_ARGS(priv
->pTVTuner
, get_ConnectInput
, &lInput
);
1079 if(FAILED(hr
)){ //Falling back to 0
1083 hr
= OLE_CALL_ARGS(priv
->pTVTuner
, get_InputType
, lInput
, &tunerInput
);
1085 if (load_freq_table(chanlist2country(priv
->tv_param
->chanlist
), tunerInput
, &(priv
->freq_table
), &(priv
->freq_table_len
), &(priv
->first_channel
)) != S_OK
) {//FIXME
1086 priv
->freq_table_len
=0;
1087 priv
->freq_table
=NULL
;
1088 mp_tmsg(MSGT_TV
, MSGL_ERR
, "tvi_dshow: Unable to load frequency table from kstvtune.ax\n");
1091 mp_tmsg(MSGT_TV
, MSGL_V
, "tvi_dshow: loaded system (%s) frequency table for country id=%d (channels:%d).\n", tunerInput
== TunerInputAntenna
? "broadcast" : "cable",
1092 chanlist2country(priv
->tv_param
->chanlist
), priv
->freq_table_len
);
1095 if (priv
->freq_table_len
<= 0)
1098 //FIXME: rewrite search algo
1100 for (i
= 0; i
< priv
->freq_table_len
; i
++) {
1101 if (nChannel
== -1 || labs(lFreq
- priv
->freq_table
[i
]) < lFreqDiff
) {
1102 nChannel
= priv
->first_channel
+ i
;
1103 lFreqDiff
= labs(lFreq
- priv
->freq_table
[i
]);
1105 mp_msg(MSGT_TV
, MSGL_DBG4
, "tvi_dshow: set_nearest_freq #%d (%ld) => %d (%ld)\n",i
+priv
->first_channel
,priv
->freq_table
[i
], nChannel
,lFreqDiff
);
1107 if (nChannel
== -1) {
1108 mp_tmsg(MSGT_TV
,MSGL_ERR
, "tvi_dshow: Unable to find nearest channel in system frequency table\n");
1111 mp_msg(MSGT_TV
, MSGL_V
, "tvi_dshow: set_nearest_freq #%d (%ld)\n",nChannel
,priv
->freq_table
[nChannel
- priv
->first_channel
]);
1112 hr
= OLE_CALL_ARGS(priv
->pTVTuner
, put_Channel
, nChannel
,
1113 AMTUNER_SUBCHAN_DEFAULT
, AMTUNER_SUBCHAN_DEFAULT
);
1115 mp_tmsg(MSGT_TV
,MSGL_ERR
,"tvi_dshow: Unable to switch to nearest channel from system frequency table. Error:0x%x\n", (unsigned int)hr
);
1122 * \brief setting frequency. decides whether use direct call/workaround
1124 * \param priv driver's private data
1125 * \param lFreq frequency in Hz
1127 * \return TVI_CONTROL_TRUE if success
1128 * \return TVI_CONTROL_FALSE if error occured
1130 * \todo check for freq boundary
1132 static int set_frequency(priv_t
* priv
, long lFreq
)
1136 mp_msg(MSGT_TV
, MSGL_DBG4
, "tvi_dshow: set_frequency called: %ld\n", lFreq
);
1137 if (!priv
->pTVTuner
)
1138 return TVI_CONTROL_FALSE
;
1139 if (priv
->direct_setfreq_call
) { //using direct call to set frequency
1140 hr
= set_frequency_direct(priv
->pTVTuner
, lFreq
);
1142 mp_tmsg(MSGT_TV
, MSGL_V
, "tvi_dshow: Unable to set frequency directly. OS built-in channels table will be used.\n");
1143 priv
->direct_setfreq_call
= 0;
1146 if (!priv
->direct_setfreq_call
) {
1147 hr
= set_nearest_freq(priv
, lFreq
);
1150 return TVI_CONTROL_FALSE
;
1152 priv
->pGrabber
->ClearBuffer(priv
->pGrabber
);
1154 return TVI_CONTROL_TRUE
;
1158 * \brief return current frequency from tuner (in Hz)
1160 * \param pTVTuner IAMTVTuner interface of tuner
1161 * \param plFreq address of variable that receives current frequency
1163 * \return S_OK success
1164 * \return E_POINTER pTVTuner==NULL || plFreq==NULL
1165 * \return apropriate error code otherwise
1167 static HRESULT
get_frequency_direct(IAMTVTuner
* pTVTuner
, long *plFreq
)
1170 KSPROPERTY_TUNER_STATUS_S TunerStatus
;
1172 IKsPropertySet
*pKSProp
;
1173 mp_msg(MSGT_TV
, MSGL_DBG4
, "tvi_dshow: get_frequency_direct called\n");
1178 hr
= OLE_QUERYINTERFACE(pTVTuner
, IID_IKsPropertySet
, pKSProp
);
1180 mp_msg(MSGT_TV
, MSGL_DBG2
, "tvi_dshow: Get freq QueryInterface failed\n");
1184 hr
= OLE_CALL_ARGS(pKSProp
, Get
, &PROPSETID_TUNER
,
1185 KSPROPERTY_TUNER_STATUS
,
1186 INSTANCEDATA_OF_PROPERTY_PTR(&TunerStatus
),
1187 INSTANCEDATA_OF_PROPERTY_SIZE(TunerStatus
),
1188 &TunerStatus
, sizeof(TunerStatus
), &cbBytes
);
1190 mp_msg(MSGT_TV
, MSGL_DBG2
, "tvi_dshow: Get freq Get failure\n");
1193 *plFreq
= TunerStatus
.CurrentFrequency
;
1198 * \brief gets current frequency
1200 * \param priv driver's private data structure
1201 * \param plFreq - pointer to long int to store frequency to (in Hz)
1203 * \return TVI_CONTROL_TRUE if success, TVI_CONTROL_FALSE otherwise
1205 static int get_frequency(priv_t
* priv
, long *plFreq
)
1209 mp_msg(MSGT_TV
, MSGL_DBG4
, "tvi_dshow: get_frequency called\n");
1211 if (!plFreq
|| !priv
->pTVTuner
)
1212 return TVI_CONTROL_FALSE
;
1214 if (priv
->direct_getfreq_call
) { //using direct call to get frequency
1215 hr
= get_frequency_direct(priv
->pTVTuner
, plFreq
);
1217 mp_tmsg(MSGT_TV
, MSGL_INFO
, "tvi_dshow: Unable to get frequency directly. OS built-in channels table will be used.\n");
1218 priv
->direct_getfreq_call
= 0;
1221 if (!priv
->direct_getfreq_call
) {
1222 hr
=OLE_CALL_ARGS(priv
->pTVTuner
, get_VideoFrequency
, plFreq
);
1224 return TVI_CONTROL_FALSE
;
1227 return TVI_CONTROL_TRUE
;
1231 * \brief get tuner capabilities
1233 * \param priv driver's private data
1235 static void get_capabilities(priv_t
* priv
)
1237 long lAvailableFormats
;
1240 long lInputPins
, lOutputPins
, lRelated
, lPhysicalType
;
1244 PIN_DIRECTION ThisPinDir
;
1246 IAMAudioInputMixer
*pIAMixer
;
1248 mp_msg(MSGT_TV
, MSGL_DBG4
, "tvi_dshow: get_capabilities called\n");
1249 if (priv
->pTVTuner
) {
1251 mp_tmsg(MSGT_TV
, MSGL_V
, "tvi_dshow: supported norms:");
1252 hr
= OLE_CALL_ARGS(priv
->pTVTuner
, get_AvailableTVFormats
,
1253 &lAvailableFormats
);
1255 tv_available_norms_count
= 0;
1257 for (i
= 0; i
< TV_NORMS_COUNT
; i
++) {
1258 if (lAvailableFormats
& tv_norms
[i
].index
) {
1259 tv_available_norms
[tv_available_norms_count
] = i
;
1260 mp_msg(MSGT_TV
, MSGL_V
, " %d=%s;",
1261 tv_available_norms_count
+ 1, tv_norms
[i
].name
);
1262 tv_available_norms_count
++;
1266 mp_msg(MSGT_TV
, MSGL_INFO
, "\n");
1268 if (priv
->pCrossbar
) {
1269 OLE_CALL_ARGS(priv
->pCrossbar
, get_PinCounts
, &lOutputPins
,
1272 tv_available_inputs
= malloc(sizeof(long) * lInputPins
);
1273 tv_available_inputs_count
= 0;
1275 mp_tmsg(MSGT_TV
, MSGL_V
, "tvi_dshow: available video inputs:");
1276 for (i
= 0; i
< lInputPins
; i
++) {
1277 OLE_CALL_ARGS(priv
->pCrossbar
, get_CrossbarPinInfo
, 1, i
,
1278 &lRelated
, &lPhysicalType
);
1280 if (lPhysicalType
< 0x1000) {
1281 tv_available_inputs
[tv_available_inputs_count
++] = i
;
1282 mp_msg(MSGT_TV
, MSGL_V
, " %d=%s;",
1283 tv_available_inputs_count
- 1,
1284 physcon2str(lPhysicalType
));
1287 mp_msg(MSGT_TV
, MSGL_INFO
, "\n");
1289 set_crossbar_input(priv
, 0);
1292 if (priv
->adev_index
!= -1) {
1293 hr
= OLE_CALL_ARGS(priv
->chains
[1]->pCaptureFilter
, EnumPins
, &pEnum
);
1296 mp_tmsg(MSGT_TV
, MSGL_V
, "tvi_dshow: available audio inputs:");
1298 while (OLE_CALL_ARGS(pEnum
, Next
, 1, &pPin
, NULL
) == S_OK
) {
1299 memset(&pi
, 0, sizeof(pi
));
1300 memset(tmp
, 0, 200);
1301 OLE_CALL_ARGS(pPin
, QueryDirection
, &ThisPinDir
);
1302 if (ThisPinDir
== PINDIR_INPUT
) {
1303 OLE_CALL_ARGS(pPin
, QueryPinInfo
, &pi
);
1304 wtoa(pi
.achName
, tmp
, 200);
1305 OLE_RELEASE_SAFE(pi
.pFilter
);
1306 mp_msg(MSGT_TV
, MSGL_V
, " %d=%s", i
, tmp
);
1307 mp_msg(MSGT_TV
, MSGL_DBG3
, " (%p)", pPin
);
1308 hr
= OLE_QUERYINTERFACE(pPin
, IID_IAMAudioInputMixer
,pIAMixer
);
1309 if (SUCCEEDED(hr
)) {
1310 if (i
== priv
->tv_param
->audio_id
) {
1311 OLE_CALL_ARGS(pIAMixer
, put_Enable
, TRUE
);
1312 if(priv
->tv_param
->volume
>0)
1313 OLE_CALL_ARGS(pIAMixer
, put_MixLevel
, 0.01 * priv
->tv_param
->volume
);
1316 OLE_CALL_ARGS(pIAMixer
, put_MixLevel
, 1.0);
1318 mp_tmsg(MSGT_TV
, MSGL_V
, "(selected)");
1320 OLE_CALL_ARGS(pIAMixer
, put_Enable
, FALSE
);
1322 OLE_CALL_ARGS(pIAMixer
, put_MixLevel
, 0.0);
1325 OLE_RELEASE_SAFE(pIAMixer
);
1327 mp_msg(MSGT_TV
, MSGL_V
, ";");
1328 OLE_RELEASE_SAFE(pPin
);
1332 mp_msg(MSGT_TV
, MSGL_INFO
, "\n");
1333 OLE_RELEASE_SAFE(pEnum
);
1338 *---------------------------------------------------------------------------------------
1340 * Filter related methods
1342 *---------------------------------------------------------------------------------------
1345 * \brief building in graph audio/video capture chain
1347 * \param priv driver's private data
1348 * \param pCaptureFilter pointer to capture device's IBaseFilter interface
1349 * \param pbuf ringbuffer data structure
1350 * \param pmt media type for chain (AM_MEDIA_TYPE)
1352 * \note routine does not frees memory, allocated for grabber_rinbuffer_s structure
1354 static HRESULT
build_sub_graph(priv_t
* priv
, chain_t
* chain
, const GUID
* ppin_category
)
1357 int nFormatProbed
= 0;
1362 IBaseFilter
*pNR
= NULL
;
1366 //No supported formats
1367 if(!chain
->arpmt
[0])
1371 hr
= OLE_CALL_ARGS(priv
->pBuilder
, FindPin
,
1372 (IUnknown
*) chain
->pCaptureFilter
,
1373 PINDIR_OUTPUT
, ppin_category
,
1374 chain
->majortype
, FALSE
, 0, &chain
->pCapturePin
);
1376 mp_msg(MSGT_TV
,MSGL_DBG2
, "tvi_dshow: FindPin(pCapturePin) call failed. Error:0x%x\n", (unsigned int)hr
);
1379 /* Addinf SampleGrabber filter for video stream */
1380 hr
= CoCreateInstance((GUID
*) & CLSID_SampleGrabber
, NULL
,CLSCTX_INPROC_SERVER
, &IID_IBaseFilter
,(void *) &chain
->pSGF
);
1382 mp_msg(MSGT_TV
,MSGL_DBG2
, "tvi_dshow: CoCreateInstance(SampleGrabber) call failed. Error:0x%x\n", (unsigned int)hr
);
1385 hr
= OLE_CALL_ARGS(priv
->pGraph
, AddFilter
, chain
->pSGF
, L
"Sample Grabber");
1387 mp_msg(MSGT_TV
,MSGL_DBG2
,"tvi_dshow: AddFilter(SampleGrabber) call failed. Error:0x%x\n", (unsigned int)hr
);
1390 hr
= OLE_CALL_ARGS(priv
->pBuilder
, FindPin
, (IUnknown
*) chain
->pSGF
,PINDIR_INPUT
, NULL
, NULL
, FALSE
, 0, &chain
->pSGIn
);
1392 mp_msg(MSGT_TV
,MSGL_DBG2
,"tvi_dshow: FindPin(pSGIn) call failed. Error:0x%x\n", (unsigned int)hr
);
1395 hr
= OLE_CALL_ARGS(priv
->pBuilder
, FindPin
, (IUnknown
*) chain
->pSGF
,PINDIR_OUTPUT
, NULL
, NULL
, FALSE
, 0, &pSGOut
);
1397 mp_msg(MSGT_TV
,MSGL_DBG2
,"tvi_dshow: FindPin(pSGOut) call failed. Error:0x%x\n", (unsigned int)hr
);
1401 /* creating ringbuffer for video samples */
1402 chain
->pCSGCB
= CSampleGrabberCB_Create(chain
->rbuf
);
1404 mp_msg(MSGT_TV
,MSGL_DBG2
, "tvi_dshow: CSampleGrabberCB_Create(pbuf) call failed. Error:0x%x\n", (unsigned int)E_OUTOFMEMORY
);
1408 /* initializing SampleGrabber filter */
1409 hr
= OLE_QUERYINTERFACE(chain
->pSGF
, IID_ISampleGrabber
, chain
->pSG
);
1411 mp_msg(MSGT_TV
,MSGL_DBG2
,"tvi_dshow: QueryInterface(IID_ISampleGrabber) call failed. Error:0x%x\n", (unsigned int)hr
);
1414 // hr = OLE_CALL_ARGS(pSG, SetCallback, (ISampleGrabberCB *) pCSGCB, 1); //we want to receive copy of sample's data
1415 hr
= OLE_CALL_ARGS(chain
->pSG
, SetCallback
, (ISampleGrabberCB
*) chain
->pCSGCB
, 0); //we want to receive sample
1418 mp_msg(MSGT_TV
,MSGL_DBG2
,"tvi_dshow: SetCallback(pSG) call failed. Error:0x%x\n", (unsigned int)hr
);
1421 hr
= OLE_CALL_ARGS(chain
->pSG
, SetOneShot
, FALSE
); //... for all frames
1423 mp_msg(MSGT_TV
,MSGL_DBG2
,"tvi_dshow: SetOneShot(pSG) call failed. Error:0x%x\n", (unsigned int)hr
);
1426 hr
= OLE_CALL_ARGS(chain
->pSG
, SetBufferSamples
, FALSE
); //... do not buffer samples in sample grabber
1428 mp_msg(MSGT_TV
,MSGL_DBG2
,"tvi_dshow: SetBufferSamples(pSG) call failed. Error:0x%x\n", (unsigned int)hr
);
1432 if(priv
->tv_param
->normalize_audio_chunks
&& chain
->type
==audio
){
1433 set_buffer_preference(20,(WAVEFORMATEX
*)(chain
->arpmt
[nFormatProbed
]->pbFormat
),chain
->pCapturePin
,chain
->pSGIn
);
1436 for(nFormatProbed
=0; chain
->arpmt
[nFormatProbed
]; nFormatProbed
++)
1438 DisplayMediaType("Probing format", chain
->arpmt
[nFormatProbed
]);
1439 hr
= OLE_CALL_ARGS(chain
->pSG
, SetMediaType
, chain
->arpmt
[nFormatProbed
]); //set desired mediatype
1441 mp_msg(MSGT_TV
,MSGL_DBG2
,"tvi_dshow: SetMediaType(pSG) call failed. Error:0x%x\n", (unsigned int)hr
);
1444 /* connecting filters together: VideoCapture --> SampleGrabber */
1445 hr
= OLE_CALL_ARGS(priv
->pGraph
, Connect
, chain
->pCapturePin
, chain
->pSGIn
);
1447 mp_msg(MSGT_TV
,MSGL_DBG2
,"tvi_dshow: Unable to create pCapturePin<->pSGIn connection. Error:0x%x\n", (unsigned int)hr
);
1453 if(!chain
->arpmt
[nFormatProbed
])
1455 mp_msg(MSGT_TV
, MSGL_WARN
, "tvi_dshow: Unable to negotiate media format\n");
1460 hr
= OLE_CALL_ARGS(chain
->pCapturePin
, ConnectionMediaType
, chain
->pmt
);
1463 mp_tmsg(MSGT_TV
, MSGL_WARN
, "tvi_dshow: Unable to get actual mediatype (Error:0x%x). Assuming equal to requested.\n", (unsigned int)hr
);
1466 if(priv
->tv_param
->hidden_video_renderer
){
1467 IEnumFilters
* pEnum
;
1468 IBaseFilter
* pFilter
;
1470 hr
=OLE_CALL_ARGS(priv
->pBuilder
,RenderStream
,NULL
,NULL
,(IUnknown
*)chain
->pCapturePin
,NULL
,NULL
);
1472 OLE_CALL_ARGS(priv
->pGraph
, EnumFilters
, &pEnum
);
1473 while (OLE_CALL_ARGS(pEnum
, Next
, 1, &pFilter
, NULL
) == S_OK
) {
1474 LPVIDEOWINDOW pVideoWindow
;
1475 hr
= OLE_QUERYINTERFACE(pFilter
, IID_IVideoWindow
, pVideoWindow
);
1478 OLE_CALL_ARGS(pVideoWindow
,put_Visible
,/* OAFALSE*/ 0);
1479 OLE_CALL_ARGS(pVideoWindow
,put_AutoShow
,/* OAFALSE*/ 0);
1480 OLE_RELEASE_SAFE(pVideoWindow
);
1482 OLE_RELEASE_SAFE(pFilter
);
1484 OLE_RELEASE_SAFE(pEnum
);
1489 Code below is disabled, because terminating chain with NullRenderer leads to jerky video.
1490 Perhaps, this happens because NullRenderer filter discards each received
1491 frame while discarded frames causes live source filter to dramatically reduce frame rate.
1493 /* adding sink for video stream */
1494 hr
= CoCreateInstance((GUID
*) & CLSID_NullRenderer
, NULL
,CLSCTX_INPROC_SERVER
, &IID_IBaseFilter
,(void *) &pNR
);
1496 mp_msg(MSGT_TV
,MSGL_DBG2
,"tvi_dshow: CoCreateInstance(NullRenderer) call failed. Error:0x%x\n", (unsigned int)hr
);
1499 hr
= OLE_CALL_ARGS(priv
->pGraph
, AddFilter
, pNR
, L
"Null Renderer");
1501 mp_msg(MSGT_TV
,MSGL_DBG2
,"tvi_dshow: AddFilter(NullRenderer) call failed. Error:0x%x\n", (unsigned int)hr
);
1504 hr
= OLE_CALL_ARGS(priv
->pBuilder
, FindPin
, (IUnknown
*) pNR
,PINDIR_INPUT
, NULL
, NULL
, FALSE
, 0, &pNRIn
);
1506 mp_msg(MSGT_TV
,MSGL_DBG2
,"tvi_dshow: FindPin(pNRIn) call failed. Error:0x%x\n", (unsigned int)hr
);
1510 Prevent ending VBI chain with NullRenderer filter, because this causes VBI pin disconnection
1512 if(memcmp(&(arpmt
[nFormatProbed
]->majortype
),&MEDIATYPE_VBI
,16)){
1513 /* connecting filters together: SampleGrabber --> NullRenderer */
1514 hr
= OLE_CALL_ARGS(priv
->pGraph
, Connect
, pSGOut
, pNRIn
);
1516 mp_msg(MSGT_TV
,MSGL_DBG2
,"tvi_dshow: Unable to create pSGOut<->pNRIn connection. Error:0x%x\n", (unsigned int)hr
);
1526 OLE_RELEASE_SAFE(pSGOut
);
1527 OLE_RELEASE_SAFE(pNR
);
1528 OLE_RELEASE_SAFE(pNRIn
);
1534 * \brief configures crossbar for grabbing video stream from given input
1536 * \param priv driver's private data
1537 * \param input index of available video input to get data from
1539 * \return TVI_CONTROL_TRUE success
1540 * \return TVI_CONTROL_FALSE error
1542 static int set_crossbar_input(priv_t
* priv
, int input
)
1545 int i
, nVideoDecoder
, nAudioDecoder
;
1546 long lInput
, lInputRelated
, lRelated
, lPhysicalType
, lOutputPins
,
1549 mp_msg(MSGT_TV
, MSGL_DBG4
, "tvi_dshow: Configuring crossbar\n");
1550 if (!priv
->pCrossbar
|| input
< 0
1551 || input
>= tv_available_inputs_count
)
1552 return TVI_CONTROL_FALSE
;
1554 OLE_CALL_ARGS(priv
->pCrossbar
, get_PinCounts
, &lOutputPins
, &lInputPins
);
1556 lInput
= tv_available_inputs
[input
];
1558 if (lInput
< 0 || lInput
>= lInputPins
)
1559 return TVI_CONTROL_FALSE
;
1561 OLE_CALL_ARGS(priv
->pCrossbar
, get_CrossbarPinInfo
, 1 /* input */ , lInput
,
1562 &lInputRelated
, &lPhysicalType
);
1564 nVideoDecoder
= nAudioDecoder
= -1;
1565 for (i
= 0; i
< lOutputPins
; i
++) {
1566 OLE_CALL_ARGS(priv
->pCrossbar
, get_CrossbarPinInfo
, 0 /*output */ , i
,
1567 &lRelated
, &lPhysicalType
);
1568 if (lPhysicalType
== PhysConn_Video_VideoDecoder
)
1570 if (lPhysicalType
== PhysConn_Audio_AudioDecoder
)
1573 if (nVideoDecoder
>= 0) {
1574 //connecting given input with video decoder
1575 hr
= OLE_CALL_ARGS(priv
->pCrossbar
, Route
, nVideoDecoder
, lInput
);
1577 mp_tmsg(MSGT_TV
,MSGL_ERR
,"Unable to connect given input to video decoder. Error:0x%x\n", (unsigned int)hr
);
1578 return TVI_CONTROL_FALSE
;
1581 if (nAudioDecoder
>= 0 && lInputRelated
>= 0) {
1582 hr
= OLE_CALL_ARGS(priv
->pCrossbar
, Route
, nAudioDecoder
,
1585 mp_tmsg(MSGT_TV
,MSGL_ERR
,"Unable to connect given input to audio decoder. Error:0x%x\n", (unsigned int)hr
);
1586 return TVI_CONTROL_FALSE
;
1589 return TVI_CONTROL_TRUE
;
1593 * \brief adjusts video control (hue,saturation,contrast,brightess)
1595 * \param priv driver's private data
1596 * \param control which control to adjust
1597 * \param value new value for control (0-100)
1599 * \return TVI_CONTROL_TRUE success
1600 * \return TVI_CONTROL_FALSE error
1602 static int set_control(priv_t
* priv
, int control
, int value
)
1604 long lMin
, lMax
, lStepping
, lDefault
, lFlags
, lValue
;
1607 mp_msg(MSGT_TV
, MSGL_DBG4
, "tvi_dshow: set_control called\n");
1608 if (value
< -100 || value
> 100 || !priv
->pVideoProcAmp
)
1609 return TVI_CONTROL_FALSE
;
1611 hr
= OLE_CALL_ARGS(priv
->pVideoProcAmp
, GetRange
, control
,
1612 &lMin
, &lMax
, &lStepping
, &lDefault
, &lFlags
);
1613 if (FAILED(hr
) || lFlags
!= VideoProcAmp_Flags_Manual
)
1614 return TVI_CONTROL_FALSE
;
1616 lValue
= lMin
+ (value
+ 100) * (lMax
- lMin
) / 200;
1618 Workaround for ATI AIW 7500. The driver reports: max=255, stepping=256
1620 if (lStepping
> lMax
) {
1621 mp_msg(MSGT_TV
, MSGL_DBG3
,
1622 "tvi_dshow: Stepping (%ld) is bigger than max value (%ld) for control %d. Assuming 1\n",
1623 lStepping
, lMax
,control
);
1626 lValue
-= lValue
% lStepping
;
1627 hr
= OLE_CALL_ARGS(priv
->pVideoProcAmp
, Set
, control
, lValue
,
1628 VideoProcAmp_Flags_Manual
);
1630 return TVI_CONTROL_FALSE
;
1632 return TVI_CONTROL_TRUE
;
1636 * \brief get current value of video control (hue,saturation,contrast,brightess)
1638 * \param priv driver's private data
1639 * \param control which control to adjust
1640 * \param pvalue address of variable thar receives current value
1642 * \return TVI_CONTROL_TRUE success
1643 * \return TVI_CONTROL_FALSE error
1645 static int get_control(priv_t
* priv
, int control
, int *pvalue
)
1647 long lMin
, lMax
, lStepping
, lDefault
, lFlags
, lValue
;
1650 mp_msg(MSGT_TV
, MSGL_DBG4
, "tvi_dshow: get_control called\n");
1651 if (!pvalue
|| !priv
->pVideoProcAmp
)
1652 return TVI_CONTROL_FALSE
;
1654 hr
= OLE_CALL_ARGS(priv
->pVideoProcAmp
, GetRange
, control
,
1655 &lMin
, &lMax
, &lStepping
, &lDefault
, &lFlags
);
1657 return TVI_CONTROL_FALSE
;
1660 return TVI_CONTROL_TRUE
;
1663 hr
= OLE_CALL_ARGS(priv
->pVideoProcAmp
, Get
, control
, &lValue
, &lFlags
);
1665 return TVI_CONTROL_FALSE
;
1667 *pvalue
= 200 * (lValue
- lMin
) / (lMax
- lMin
) - 100;
1669 return TVI_CONTROL_TRUE
;
1673 * \brief create AM_MEDIA_TYPE structure, corresponding to given FourCC code and width/height/fps
1674 * \param fcc FourCC code for video format
1675 * \param width picture width
1676 * \param height pciture height
1677 * \param fps frames per second (required for bitrate calculation)
1679 * \return pointer to AM_MEDIA_TYPE structure if success, NULL - otherwise
1681 static AM_MEDIA_TYPE
* create_video_format(int fcc
, int width
, int height
, int fps
)
1685 VIDEOINFOHEADER vHdr
;
1687 /* Check given fcc in lookup table*/
1688 for(i
=0; img_fmt_list
[i
].fmt
&& img_fmt_list
[i
].fmt
!=fcc
; i
++) /* NOTHING */;
1689 if(!img_fmt_list
[i
].fmt
)
1692 memset(&mt
, 0, sizeof(AM_MEDIA_TYPE
));
1693 memset(&vHdr
, 0, sizeof(VIDEOINFOHEADER
));
1695 vHdr
.bmiHeader
.biSize
= sizeof(vHdr
.bmiHeader
);
1696 vHdr
.bmiHeader
.biWidth
= width
;
1697 vHdr
.bmiHeader
.biHeight
= height
;
1698 //FIXME: is biPlanes required too?
1699 //vHdr.bmiHeader.biPlanes = img_fmt_list[i].nPlanes;
1700 vHdr
.bmiHeader
.biBitCount
= img_fmt_list
[i
].nBits
;
1701 vHdr
.bmiHeader
.biCompression
= img_fmt_list
[i
].nCompression
;
1702 vHdr
.bmiHeader
.biSizeImage
= width
* height
* img_fmt_list
[i
].nBits
/ 8;
1703 vHdr
.dwBitRate
= vHdr
.bmiHeader
.biSizeImage
* 8 * fps
;
1705 mt
.pbFormat
= (char*)&vHdr
;
1706 mt
.cbFormat
= sizeof(vHdr
);
1708 mt
.majortype
= MEDIATYPE_Video
;
1709 mt
.subtype
= *img_fmt_list
[i
].subtype
;
1710 mt
.formattype
= FORMAT_VideoInfo
;
1712 mt
.bFixedSizeSamples
= 1;
1713 mt
.bTemporalCompression
= 0;
1714 mt
.lSampleSize
= vHdr
.bmiHeader
.biSizeImage
;
1716 return CreateMediaType(&mt
);
1720 * \brief extracts fcc,width,height from AM_MEDIA_TYPE
1722 * \param pmt pointer to AM_MEDIA_TYPE to extract data from
1723 * \param pfcc address of variable that receives FourCC
1724 * \param pwidth address of variable that receives width
1725 * \param pheight address of variable that recevies height
1727 * \return 1 if data extracted successfully, 0 - otherwise
1729 static int extract_video_format(AM_MEDIA_TYPE
* pmt
, int *pfcc
,
1730 int *pwidth
, int *pheight
)
1732 mp_msg(MSGT_TV
, MSGL_DBG4
, "tvi_dshow: extract_video_format called\n");
1737 if (memcmp(&(pmt
->formattype
), &FORMAT_VideoInfo
, 16) != 0)
1740 *pfcc
= subtype2imgfmt(&(pmt
->subtype
));
1742 *pwidth
= ((VIDEOINFOHEADER
*) pmt
->pbFormat
)->bmiHeader
.biWidth
;
1744 *pheight
= ((VIDEOINFOHEADER
*) pmt
->pbFormat
)->bmiHeader
.biHeight
;
1749 * \brief extracts samplerate,bits,channels from AM_MEDIA_TYPE
1751 * \param pmt pointer to AM_MEDIA_TYPE to extract data from
1752 * \param pfcc address of variable that receives samplerate
1753 * \param pwidth address of variable that receives number of bits per sample
1754 * \param pheight address of variable that recevies number of channels
1756 * \return 1 if data extracted successfully, 0 - otherwise
1758 static int extract_audio_format(AM_MEDIA_TYPE
* pmt
, int *psamplerate
,
1759 int *pbits
, int *pchannels
)
1761 mp_msg(MSGT_TV
, MSGL_DBG4
, "tvi_dshow: extract_audio_format called\n");
1766 if (memcmp(&(pmt
->formattype
), &FORMAT_WaveFormatEx
, 16) != 0)
1769 *psamplerate
= ((WAVEFORMATEX
*) pmt
->pbFormat
)->nSamplesPerSec
;
1771 *pbits
= ((WAVEFORMATEX
*) pmt
->pbFormat
)->wBitsPerSample
;
1773 *pchannels
= ((WAVEFORMATEX
*) pmt
->pbFormat
)->nChannels
;
1778 * \brief checks if AM_MEDIA_TYPE compatible with given samplerate,bits,channels
1780 * \param pmt pointer to AM_MEDIA_TYPE for check
1781 * \param samplerate audio samplerate
1782 * \param bits bits per sample
1783 * \param channels number of audio channels
1785 * \return 1 if AM_MEDIA_TYPE compatible
1788 static int check_audio_format(AM_MEDIA_TYPE
* pmt
, int samplerate
,
1789 int bits
, int channels
)
1791 mp_msg(MSGT_TV
, MSGL_DBG4
, "tvi_dshow: check_audio_format called\n");
1794 if (memcmp(&(pmt
->majortype
), &MEDIATYPE_Audio
, 16) != 0)
1796 if (memcmp(&(pmt
->subtype
), &MEDIASUBTYPE_PCM
, 16) != 0)
1798 if (memcmp(&(pmt
->formattype
), &FORMAT_WaveFormatEx
, 16) != 0)
1802 if (((WAVEFORMATEX
*) pmt
->pbFormat
)->nSamplesPerSec
!= samplerate
)
1804 if (((WAVEFORMATEX
*) pmt
->pbFormat
)->wBitsPerSample
!= bits
)
1807 && ((WAVEFORMATEX
*) pmt
->pbFormat
)->nChannels
!= channels
)
1814 * \brief checks if AM_MEDIA_TYPE compatible with given fcc,width,height
1816 * \param pmt pointer to AM_MEDIA_TYPE for check
1817 * \param fcc FourCC (compression)
1818 * \param width width of picture
1819 * \param height height of picture
1821 * \return 1 if AM_MEDIA_TYPE compatible
1825 * width and height are currently not used
1828 * add width/height check
1830 static int check_video_format(AM_MEDIA_TYPE
* pmt
, int fcc
, int width
,
1833 mp_msg(MSGT_TV
, MSGL_DBG4
, "tvi_dshow: check_video_format called\n");
1836 if (memcmp(&(pmt
->majortype
), &MEDIATYPE_Video
, 16) != 0)
1838 if (subtype2imgfmt(&(pmt
->subtype
)) != fcc
)
1844 * \brief converts DirectShow subtype to MPlayer's IMGFMT
1846 * \param subtype DirectShow subtype for video format
1848 * \return MPlayer's IMGFMT or 0 if error occured
1850 static int subtype2imgfmt(const GUID
* subtype
)
1853 for (i
= 0; img_fmt_list
[i
].fmt
; i
++) {
1854 if (memcmp(subtype
, img_fmt_list
[i
].subtype
, 16) == 0)
1855 return img_fmt_list
[i
].fmt
;
1861 * \brief prints filter name and it pins
1863 * \param pFilter - IBaseFilter to get data from
1865 * \return S_OK if success, error code otherwise
1867 static HRESULT
show_filter_info(IBaseFilter
* pFilter
)
1871 LPENUMPINS pEnum
= 0;
1873 PIN_DIRECTION ThisPinDir
;
1878 mp_msg(MSGT_TV
, MSGL_DBG4
, "tvi_dshow: show_filter_info called\n");
1879 memset(&fi
, 0, sizeof(fi
));
1880 memset(tmp
, 0, 200);
1882 OLE_CALL_ARGS(pFilter
, QueryFilterInfo
, &fi
);
1883 OLE_RELEASE_SAFE(fi
.pGraph
);
1884 wtoa(fi
.achName
, tmp
, 200);
1885 mp_msg(MSGT_TV
, MSGL_DBG2
, "tvi_dshow: BaseFilter (%p): Name=%s, Graph=%p output pins:",
1886 pFilter
, tmp
, fi
.pGraph
);
1887 hr
= OLE_CALL_ARGS(pFilter
, EnumPins
, &pEnum
);
1891 while (OLE_CALL_ARGS(pEnum
, Next
, 1, &pPin
, NULL
) == S_OK
) {
1892 memset(&pi
, 0, sizeof(pi
));
1893 memset(tmp
, 0, 200);
1894 OLE_CALL_ARGS(pPin
, QueryDirection
, &ThisPinDir
);
1895 if (ThisPinDir
== PINDIR_OUTPUT
) {
1896 OLE_CALL_ARGS(pPin
, QueryPinInfo
, &pi
);
1897 wtoa(pi
.achName
, tmp
, 200);
1898 OLE_RELEASE_SAFE(pi
.pFilter
);
1899 mp_msg(MSGT_TV
, MSGL_DBG2
, " %d=%s", i
, tmp
);
1900 mp_msg(MSGT_TV
, MSGL_DBG3
, " (%p)", pPin
);
1901 mp_msg(MSGT_TV
, MSGL_DBG2
, ";");
1902 OLE_RELEASE_SAFE(pPin
);
1906 mp_msg(MSGT_TV
, MSGL_DBG2
, "\n");
1907 OLE_RELEASE_SAFE(pEnum
);
1912 * \brief gets device's frendly in ANSI encoding
1914 * \param pM IMoniker interface, got in enumeration process
1915 * \param category device category
1917 * \return TVI_CONTROL_TRUE if operation succeded, TVI_CONTROL_FALSE - otherwise
1919 static int get_device_name(IMoniker
* pM
, char *pBuf
, int nLen
)
1923 IPropertyBag
*pPropBag
;
1924 hr
= OLE_CALL_ARGS(pM
, BindToStorage
, 0, 0, &IID_IPropertyBag
,(void *) &pPropBag
);
1926 mp_msg(MSGT_TV
, MSGL_DBG2
, "tvi_dshow: Call to BindToStorage failed\n");
1927 return TVI_CONTROL_FALSE
;
1930 hr
= OLE_CALL_ARGS(pPropBag
, Read
, L
"Description", (LPVARIANT
) & var
,
1933 hr
= OLE_CALL_ARGS(pPropBag
, Read
, L
"FriendlyName", (LPVARIANT
) & var
,
1936 OLE_RELEASE_SAFE(pPropBag
);
1937 if (SUCCEEDED(hr
)) {
1938 wtoa(var
.bstrVal
, pBuf
, nLen
);
1939 return TVI_CONTROL_TRUE
;
1941 return TVI_CONTROL_FALSE
;
1945 * \brief find capture device at given index
1947 * \param index device index to search for (-1 mean only print available)
1948 * \param category device category
1950 * \return IBaseFilter interface for capture device with given index
1952 * Sample values for category:
1953 * CLSID_VideoInputDeviceCategory - Video Capture Sources
1954 * CLSID_AudioInputDeviceCategory - Audio Capture Sources
1955 * See DirectShow SDK documentation for other possible values
1957 static IBaseFilter
*find_capture_device(int index
, REFCLSID category
)
1959 IBaseFilter
*pFilter
= NULL
;
1960 ICreateDevEnum
*pDevEnum
= NULL
;
1961 IEnumMoniker
*pClassEnum
= NULL
;
1966 char tmp
[DEVICE_NAME_MAX_LEN
+ 1];
1967 hr
= CoCreateInstance((GUID
*) & CLSID_SystemDeviceEnum
, NULL
,
1968 CLSCTX_INPROC_SERVER
, &IID_ICreateDevEnum
,
1969 (void *) &pDevEnum
);
1971 mp_msg(MSGT_TV
, MSGL_DBG2
, "tvi_dshow: Unable to create device enumerator\n");
1975 hr
= OLE_CALL_ARGS(pDevEnum
, CreateClassEnumerator
, category
, &pClassEnum
, 0);
1976 OLE_RELEASE_SAFE(pDevEnum
);
1978 mp_msg(MSGT_TV
, MSGL_DBG2
, "tvi_dshow: Unable to create class enumerator\n");
1981 if (hr
== S_FALSE
) {
1982 mp_msg(MSGT_TV
, MSGL_DBG2
, "tvi_dshow: No capture devices found\n");
1986 OLE_CALL(pClassEnum
,Reset
);
1987 for (i
= 0; OLE_CALL_ARGS(pClassEnum
, Next
, 1, &pM
, &cFetched
) == S_OK
; i
++) {
1988 if(get_device_name(pM
, tmp
, DEVICE_NAME_MAX_LEN
)!=TVI_CONTROL_TRUE
)
1989 mp_tmsg(MSGT_TV
, MSGL_ERR
, "tvi_dshow: Unable to get name for device #%d\n", i
);
1991 mp_tmsg(MSGT_TV
, MSGL_V
, "tvi_dshow: Device #%d: %s\n", i
, tmp
);
1992 if (index
!= -1 && i
== index
) {
1993 mp_tmsg(MSGT_TV
, MSGL_INFO
, "tvi_dshow: Using device #%d: %s\n", index
, tmp
);
1994 hr
= OLE_CALL_ARGS(pM
, BindToObject
, 0, 0, &IID_IBaseFilter
,(void *) &pFilter
);
1998 OLE_RELEASE_SAFE(pM
);
2000 if (index
!= -1 && !pFilter
) {
2001 mp_tmsg(MSGT_TV
, MSGL_ERR
, "tvi_dshow: Device #%d not found\n",
2004 OLE_RELEASE_SAFE(pClassEnum
);
2010 * \brief get array of available formats through call to IAMStreamConfig::GetStreamCaps
2012 * \praram[in] chain chain data structure
2014 * \return S_OK success
2015 * \return E_POINTER one of parameters is NULL
2016 * \return E_FAIL required size of buffer is unknown for given media type
2017 * \return E_OUTOFMEMORY not enough memory
2018 * \return other error code from called methods
2021 * last items of chain->arpmt and chain->arStreamCaps will be NULL
2023 static HRESULT
get_available_formats_stream(chain_t
*chain
)
2025 AM_MEDIA_TYPE
**arpmt
;
2032 mp_msg(MSGT_TV
, MSGL_DBG4
,
2033 "tvi_dshow: get_available_formats_stream called\n");
2035 if (!chain
->pStreamConfig
)
2038 hr
=OLE_CALL_ARGS(chain
->pStreamConfig
, GetNumberOfCapabilities
, &count
, &size
);
2040 mp_msg(MSGT_TV
, MSGL_DBG4
,
2041 "tvi_dshow: Call to GetNumberOfCapabilities failed (get_available_formats_stream)\n");
2044 if (chain
->type
== video
){
2045 if (size
!= sizeof(VIDEO_STREAM_CONFIG_CAPS
)) {
2046 mp_msg(MSGT_TV
, MSGL_DBG4
,
2047 "tvi_dshow: Wrong video structure size for GetNumberOfCapabilities (get_available_formats_stream)\n");
2050 } else if (chain
->type
== audio
){
2051 if (size
!= sizeof(AUDIO_STREAM_CONFIG_CAPS
)) {
2052 mp_msg(MSGT_TV
, MSGL_DBG4
,
2053 "tvi_dshow: Wrong audio structure size for GetNumberOfCapabilities (get_available_formats_stream)\n");
2057 mp_tmsg(MSGT_TV
, MSGL_ERR
, "tvi_dshow: Unsupported media type passed to %s\n","get_available_formats_stream");
2062 arpmt
= malloc((count
+ 1) * sizeof(AM_MEDIA_TYPE
*));
2064 memset(arpmt
, 0, (count
+ 1) * sizeof(AM_MEDIA_TYPE
*));
2066 pBuf
= malloc((count
+ 1) * sizeof(void *));
2068 memset(pBuf
, 0, (count
+ 1) * sizeof(void *));
2070 for (i
= 0; i
< count
; i
++) {
2071 pBuf
[i
] = malloc(size
);
2076 hr
= OLE_CALL_ARGS(chain
->pStreamConfig
, GetStreamCaps
, i
,
2077 &(arpmt
[i
]), pBuf
[i
]);
2082 chain
->arpmt
= arpmt
;
2083 chain
->arStreamCaps
= pBuf
;
2089 for (i
= 0; i
< count
; i
++) {
2092 if (arpmt
&& arpmt
[i
])
2093 DeleteMediaType(arpmt
[i
]);
2098 mp_msg(MSGT_TV
, MSGL_DBG4
, "tvi_dshow: Call to GetStreamCaps failed (get_available_formats_stream)\n");
2101 return E_OUTOFMEMORY
;
2107 * \brief returns allocates an array and store available media formats for given pin type to it
2109 * \param pBuilder ICaptureGraphBuilder2 interface of graph builder
2110 * \param chain chain data structure
2112 * \return S_OK success
2113 * \return E_POINTER one of given pointers is null
2114 * \return apropriate error code otherwise
2116 static HRESULT
get_available_formats_pin(ICaptureGraphBuilder2
* pBuilder
,
2119 IEnumMediaTypes
*pEnum
;
2125 AM_MEDIA_TYPE
**arpmt
; //This will be real array
2126 VIDEO_STREAM_CONFIG_CAPS
*pVideoCaps
;
2127 AUDIO_STREAM_CONFIG_CAPS
*pAudioCaps
;
2130 mp_msg(MSGT_TV
, MSGL_DBG4
,
2131 "tvi_dshow: get_available_formats_pin called\n");
2132 if (!pBuilder
|| !chain
->pCaptureFilter
)
2135 if (!chain
->pCapturePin
)
2137 hr
= OLE_CALL_ARGS(pBuilder
, FindPin
,
2138 (IUnknown
*) chain
->pCaptureFilter
,
2139 PINDIR_OUTPUT
, &PIN_CATEGORY_CAPTURE
,
2140 chain
->majortype
, FALSE
, 0, &chain
->pCapturePin
);
2142 if (!chain
->pCapturePin
)
2145 if (chain
->type
== video
) {
2146 size
= sizeof(VIDEO_STREAM_CONFIG_CAPS
);
2147 } else if (chain
->type
== audio
) {
2148 size
= sizeof(AUDIO_STREAM_CONFIG_CAPS
);
2150 mp_tmsg(MSGT_TV
, MSGL_ERR
, "tvi_dshow: Unsupported media type passed to %s\n","get_available_formats_pin");
2154 hr
= OLE_CALL_ARGS(chain
->pCapturePin
, EnumMediaTypes
, &pEnum
);
2156 mp_msg(MSGT_TV
, MSGL_DBG4
,
2157 "tvi_dshow: Call to EnumMediaTypes failed (get_available_formats_pin)\n");
2160 for (i
= 0; OLE_CALL_ARGS(pEnum
, Next
, 1, &pmt
, &cFetched
) == S_OK
; i
++) {
2164 OLE_CALL(pEnum
,Reset
);
2167 arpmt
= malloc((count
+ 1) * sizeof(AM_MEDIA_TYPE
*));
2169 return E_OUTOFMEMORY
;
2170 memset(arpmt
, 0, (count
+ 1) * sizeof(AM_MEDIA_TYPE
*));
2174 && OLE_CALL_ARGS(pEnum
, Next
, 1, &(arpmt
[i
]), &cFetched
) == S_OK
;
2177 OLE_RELEASE_SAFE(pEnum
);
2180 pBuf
= malloc((count
+ 1) * sizeof(void *));
2182 for (i
= 0; i
< count
; i
++)
2184 DeleteMediaType(arpmt
[i
]);
2186 return E_OUTOFMEMORY
;
2188 memset(pBuf
, 0, (count
+ 1) * sizeof(void *));
2190 for (i
= 0; i
< count
; i
++) {
2191 pBuf
[i
] = malloc(size
);
2194 memset(pBuf
[i
], 0, size
);
2196 if (chain
->type
== video
) {
2197 pVideoCaps
= (VIDEO_STREAM_CONFIG_CAPS
*) pBuf
[i
];
2198 extract_video_format(arpmt
[i
], NULL
, &p1
, &p2
);
2199 pVideoCaps
->MaxOutputSize
.cx
= pVideoCaps
->MinOutputSize
.cx
=
2201 pVideoCaps
->MaxOutputSize
.cy
= pVideoCaps
->MinOutputSize
.cy
=
2204 pAudioCaps
= (AUDIO_STREAM_CONFIG_CAPS
*) pBuf
[i
];
2205 extract_audio_format(arpmt
[i
], &p1
, &p2
, &p3
);
2206 pAudioCaps
->MaximumSampleFrequency
=
2207 pAudioCaps
->MinimumSampleFrequency
= p1
;
2208 pAudioCaps
->MaximumBitsPerSample
=
2209 pAudioCaps
->MinimumBitsPerSample
= p2
;
2210 pAudioCaps
->MaximumChannels
= pAudioCaps
->MinimumChannels
= p3
;
2215 for (i
= 0; i
< count
; i
++) {
2217 DeleteMediaType(arpmt
[i
]);
2222 return E_OUTOFMEMORY
;
2224 chain
->arpmt
= arpmt
;
2225 chain
->arStreamCaps
= pBuf
;
2231 *---------------------------------------------------------------------------------------
2235 *---------------------------------------------------------------------------------------
2238 * \brief fills given buffer with audio data (usually one block)
2240 * \param priv driver's private data structure
2241 * \param buffer buffer to store data to
2242 * \param len buffer's size in bytes (usually one block size)
2244 * \return audio pts if audio present, 1 - otherwise
2246 static double grab_audio_frame(priv_t
* priv
, char *buffer
, int len
)
2251 grabber_ringbuffer_t
*rb
= priv
->chains
[1]->rbuf
;
2252 grabber_ringbuffer_t
*vrb
= priv
->chains
[0]->rbuf
;
2254 if (!rb
|| !rb
->ringbuffer
)
2257 if(vrb
&& vrb
->tStart
<0){
2258 memset(buffer
,0,len
);
2261 if(vrb
&& rb
->tStart
<0)
2262 rb
->tStart
=vrb
->tStart
;
2264 if (len
< rb
->blocksize
)
2267 bytes
= rb
->blocksize
;
2269 mp_msg(MSGT_TV
, MSGL_DBG3
,"tvi_dshow: FillBuffer (audio) called. %d blocks in buffer, %d bytes requested\n",
2272 mp_msg(MSGT_TV
,MSGL_DBG4
,"tvi_dshow: waiting for frame\n");
2273 for(i
=0;i
<1000 && !rb
->count
;i
++) usec_sleep(1000);
2275 mp_msg(MSGT_TV
,MSGL_DBG4
,"tvi_dshow: waiting timeout\n");
2278 mp_msg(MSGT_TV
,MSGL_DBG4
,"tvi_dshow: got frame!\n");
2281 EnterCriticalSection(rb
->pMutex
);
2282 pts
=rb
->dpts
[rb
->head
]-rb
->tStart
;
2283 memcpy(buffer
, rb
->ringbuffer
[rb
->head
], bytes
);
2284 rb
->head
= (rb
->head
+ 1) % rb
->buffersize
;
2286 LeaveCriticalSection(rb
->pMutex
);
2291 * \brief returns audio frame size
2293 * \param priv driver's private data structure
2295 * \return audio block size if audio enabled and 1 - otherwise
2297 static int get_audio_framesize(priv_t
* priv
)
2299 if (!priv
->chains
[1]->rbuf
)
2300 return 1; //no audio
2301 mp_msg(MSGT_TV
,MSGL_DBG3
,"get_audio_framesize: %d\n",priv
->chains
[1]->rbuf
->blocksize
);
2302 return priv
->chains
[1]->rbuf
->blocksize
;
2305 static int vbi_get_props(priv_t
* priv
,tt_stream_props
* ptsp
)
2308 return TVI_CONTROL_FALSE
;
2314 ptsp
->sampling_rate
=27e6
;
2315 ptsp
->samples_per_line
=720;
2320 ptsp
->bufsize
= ptsp
->samples_per_line
* (ptsp
->count
[0] + ptsp
->count
[1]);
2322 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",
2323 ptsp
->sampling_rate
,
2325 ptsp
->samples_per_line
,
2326 ptsp
->interlaced
?"Yes":"No",
2330 return TVI_CONTROL_TRUE
;
2333 static void vbi_grabber(priv_t
* priv
)
2335 grabber_ringbuffer_t
*rb
= priv
->chains
[2]->rbuf
;
2338 if (!rb
|| !rb
->ringbuffer
)
2341 buf
=calloc(1,rb
->blocksize
);
2342 for(i
=0; i
<23 && rb
->count
; i
++){
2343 memcpy(buf
,rb
->ringbuffer
[rb
->head
],rb
->blocksize
);
2344 teletext_control(priv
->priv_vbi
,TV_VBI_CONTROL_DECODE_PAGE
,&buf
);
2345 rb
->head
= (rb
->head
+ 1) % rb
->buffersize
;
2352 * \brief fills given buffer with video data (usually one frame)
2354 * \param priv driver's private data structure
2355 * \param buffer buffer to store data to
2356 * \param len buffer's size in bytes (usually one frame size)
2358 * \return frame size if video present, 0 - otherwise
2360 static double grab_video_frame(priv_t
* priv
, char *buffer
, int len
)
2365 grabber_ringbuffer_t
*rb
= priv
->chains
[0]->rbuf
;
2367 if (!rb
|| !rb
->ringbuffer
)
2369 if (len
< rb
->blocksize
)
2372 bytes
= rb
->blocksize
;
2374 mp_msg(MSGT_TV
, MSGL_DBG3
,"tvi_dshow: FillBuffer (video) called. %d blocks in buffer, %d bytes requested\n",
2377 mp_msg(MSGT_TV
,MSGL_DBG4
,"tvi_dshow: waiting for frame\n");
2378 for(i
=0;i
<1000 && !rb
->count
;i
++) usec_sleep(1000);
2380 mp_msg(MSGT_TV
,MSGL_DBG4
,"tvi_dshow: waiting timeout\n");
2383 mp_msg(MSGT_TV
,MSGL_DBG4
,"tvi_dshow: got frame!\n");
2385 EnterCriticalSection(rb
->pMutex
);
2387 rb
->tStart
=rb
->dpts
[rb
->head
];
2388 pts
=rb
->dpts
[rb
->head
]-rb
->tStart
;
2389 memcpy(buffer
, rb
->ringbuffer
[rb
->head
], bytes
);
2390 rb
->head
= (rb
->head
+ 1) % rb
->buffersize
;
2392 LeaveCriticalSection(rb
->pMutex
);
2399 * \brief returns frame size
2401 * \param priv driver's private data structure
2403 * \return frame size if video present, 0 - otherwise
2405 static int get_video_framesize(priv_t
* priv
)
2407 // if(!priv->pmtVideo) return 1; //no video
2408 // return priv->pmtVideo->lSampleSize;
2409 if (!priv
->chains
[0]->rbuf
)
2410 return 1; //no video
2411 mp_msg(MSGT_TV
,MSGL_DBG3
,"geT_video_framesize: %d\n",priv
->chains
[0]->rbuf
->blocksize
);
2412 return priv
->chains
[0]->rbuf
->blocksize
;
2416 * \brief calculate audio buffer size
2417 * \param video_buf_size size of video buffer in bytes
2418 * \param video_bitrate video bit rate
2419 * \param audio_bitrate audio bit rate
2420 * \return audio buffer isze in bytes
2422 * \remarks length of video buffer and resulted audio buffer calculated in
2423 * seconds will be the same.
2425 static inline int audio_buf_size_from_video(int video_buf_size
, int video_bitrate
, int audio_bitrate
)
2427 int audio_buf_size
= audio_bitrate
* (video_buf_size
/ video_bitrate
);
2428 mp_msg(MSGT_TV
,MSGL_DBG2
,"tvi_dshow: Audio capture buffer: %d * %d / %d = %d\n",
2429 audio_bitrate
,video_buf_size
,video_bitrate
,audio_buf_size
);
2430 return audio_buf_size
;
2434 * \brief common chain initialization routine
2435 * \param chain chain data structure
2437 * \note pCaptureFilter member should be initialized before call to this routine
2439 static HRESULT
init_chain_common(ICaptureGraphBuilder2
*pBuilder
, chain_t
*chain
)
2444 if(!chain
->pCaptureFilter
)
2447 show_filter_info(chain
->pCaptureFilter
);
2449 hr
= OLE_CALL_ARGS(pBuilder
, FindPin
,
2450 (IUnknown
*) chain
->pCaptureFilter
,
2451 PINDIR_OUTPUT
, chain
->pin_category
,
2452 chain
->majortype
, FALSE
, 0, &chain
->pCapturePin
);
2455 mp_msg(MSGT_TV
,MSGL_DBG2
, "tvi_dshow: FindPin(pCapturePin) call failed. Error:0x%x\n", (unsigned int)hr
);
2459 hr
= OLE_CALL_ARGS(pBuilder
, FindInterface
,
2460 chain
->pin_category
,
2462 chain
->pCaptureFilter
,
2463 &IID_IAMStreamConfig
,
2464 (void **) &(chain
->pStreamConfig
));
2466 chain
->pStreamConfig
= NULL
;
2469 Getting available video formats (last pointer in array will be NULL)
2470 First tryin to call IAMStreamConfig::GetStreamCaos. this will give us additional information such as
2471 min/max picture dimensions, etc. If this call fails trying IPIn::EnumMediaTypes with default
2474 hr
= get_available_formats_stream(chain
);
2476 mp_msg(MSGT_TV
, MSGL_DBG2
, "Unable to use IAMStreamConfig for retriving available formats (Error:0x%x). Using EnumMediaTypes instead\n", (unsigned int)hr
);
2477 hr
= get_available_formats_pin(pBuilder
, chain
);
2482 chain
->nFormatUsed
= 0;
2484 //If argument to CreateMediaType is NULL then result will be NULL too.
2485 chain
->pmt
= CreateMediaType(chain
->arpmt
[0]);
2487 for (i
= 0; chain
->arpmt
[i
]; i
++)
2488 DisplayMediaType("Available format", chain
->arpmt
[i
]);
2493 * \brief build video stream chain in graph
2494 * \param priv private data structure
2496 * \return S_OK if chain was built successfully, apropriate error code otherwise
2498 static HRESULT
build_video_chain(priv_t
*priv
)
2502 if(priv
->chains
[0]->rbuf
)
2505 if (priv
->chains
[0]->pStreamConfig
) {
2506 hr
= OLE_CALL_ARGS(priv
->chains
[0]->pStreamConfig
, SetFormat
, priv
->chains
[0]->pmt
);
2508 mp_tmsg(MSGT_TV
,MSGL_ERR
,"tvi_dshow: Unable to select video format. Error:0x%x\n", (unsigned int)hr
);
2512 priv
->chains
[0]->rbuf
=calloc(1,sizeof(grabber_ringbuffer_t
));
2513 if(!priv
->chains
[0]->rbuf
)
2514 return E_OUTOFMEMORY
;
2516 if (priv
->tv_param
->buffer_size
>= 0) {
2517 priv
->chains
[0]->rbuf
->buffersize
= priv
->tv_param
->buffer_size
;
2519 priv
->chains
[0]->rbuf
->buffersize
= 16;
2522 priv
->chains
[0]->rbuf
->buffersize
*= 1024 * 1024;
2523 hr
=build_sub_graph(priv
, priv
->chains
[0], &PIN_CATEGORY_CAPTURE
);
2525 mp_tmsg(MSGT_TV
, MSGL_ERR
, "tvi_dshow: Unable to build video chain of capture graph. Error:0x%x\n",(unsigned int)hr
);
2532 * \brief build audio stream chain in graph
2533 * \param priv private data structure
2535 * \return S_OK if chain was built successfully, apropriate error code otherwise
2537 static HRESULT
build_audio_chain(priv_t
*priv
)
2541 if(priv
->chains
[1]->rbuf
)
2544 if(priv
->immediate_mode
)
2547 if (priv
->chains
[1]->pStreamConfig
) {
2548 hr
= OLE_CALL_ARGS(priv
->chains
[1]->pStreamConfig
, SetFormat
,
2549 priv
->chains
[1]->pmt
);
2551 mp_tmsg(MSGT_TV
,MSGL_ERR
,"tvi_dshow: Unable to select audio format. Error:0x%x\n", (unsigned int)hr
);
2555 if(priv
->chains
[1]->pmt
){
2556 priv
->chains
[1]->rbuf
=calloc(1,sizeof(grabber_ringbuffer_t
));
2557 if(!priv
->chains
[1]->rbuf
)
2558 return E_OUTOFMEMORY
;
2560 /* let the audio buffer be the same size (in seconds) than video one */
2561 priv
->chains
[1]->rbuf
->buffersize
=audio_buf_size_from_video(
2562 priv
->chains
[0]->rbuf
->buffersize
,
2563 (((VIDEOINFOHEADER
*) priv
->chains
[0]->pmt
->pbFormat
)->dwBitRate
),
2564 (((WAVEFORMATEX
*) (priv
->chains
[1]->pmt
->pbFormat
))->nAvgBytesPerSec
));
2566 hr
=build_sub_graph(priv
, priv
->chains
[1],&PIN_CATEGORY_CAPTURE
);
2568 mp_tmsg(MSGT_TV
, MSGL_ERR
, "tvi_dshow: Unable to build audio chain of capture graph. Error:0x%x\n",(unsigned int)hr
);
2576 * \brief build VBI stream chain in graph
2577 * \param priv private data structure
2579 * \return S_OK if chain was built successfully, apropriate error code otherwise
2581 static HRESULT
build_vbi_chain(priv_t
*priv
)
2585 if(priv
->chains
[2]->rbuf
)
2588 if(priv
->tv_param
->teletext
.device
)
2590 priv
->chains
[2]->rbuf
=calloc(1,sizeof(grabber_ringbuffer_t
));
2591 if(!priv
->chains
[2]->rbuf
)
2592 return E_OUTOFMEMORY
;
2594 init_ringbuffer(priv
->chains
[2]->rbuf
,24,priv
->tsp
.bufsize
);
2596 hr
=build_sub_graph(priv
, priv
->chains
[2],&PIN_CATEGORY_VBI
);
2598 mp_tmsg(MSGT_TV
, MSGL_ERR
, "tvi_dshow: Unable to build VBI chain of capture graph. Error:0x%x\n",(unsigned int)hr
);
2606 * \brief playback/capture real start
2608 * \param priv driver's private data structure
2610 * \return 1 if success, 0 - otherwise
2612 * TODO: move some code from init() here
2614 static int start(priv_t
* priv
)
2618 hr
= build_video_chain(priv
);
2622 hr
= build_audio_chain(priv
);
2626 hr
= build_vbi_chain(priv
);
2631 Graph is ready to capture. Starting graph.
2633 if (mp_msg_test(MSGT_TV
, MSGL_DBG2
)) {
2634 mp_msg(MSGT_TV
, MSGL_DBG2
, "Debug pause 10sec\n");
2635 usec_sleep(10000000);
2636 mp_msg(MSGT_TV
, MSGL_DBG2
, "Debug pause end\n");
2638 if (!priv
->pMediaControl
) {
2639 mp_tmsg(MSGT_TV
,MSGL_ERR
,"tvi_dshow: Unable to get IMediaControl interface. Error:0x%x\n",(unsigned int)E_POINTER
);
2642 hr
= OLE_CALL(priv
->pMediaControl
, Run
);
2644 mp_tmsg(MSGT_TV
,MSGL_ERR
,"tvi_dshow: Unable to start graph! Error:0x%x\n", (unsigned int)hr
);
2647 mp_msg(MSGT_TV
, MSGL_DBG2
, "tvi_dshow: Graph is started.\n");
2654 * \brief driver initialization
2656 * \param priv driver's private data structure
2658 * \return 1 if success, 0 - otherwise
2660 static int init(priv_t
* priv
)
2664 long lInput
, lTunerInput
;
2665 IEnumFilters
*pEnum
;
2666 IBaseFilter
*pFilter
;
2675 priv
->chains
[i
] = calloc(1, sizeof(chain_t
));
2677 priv
->chains
[0]->type
=video
;
2678 priv
->chains
[0]->majortype
=&MEDIATYPE_Video
;
2679 priv
->chains
[0]->pin_category
=&PIN_CATEGORY_CAPTURE
;
2680 priv
->chains
[1]->type
=audio
;
2681 priv
->chains
[1]->majortype
=&MEDIATYPE_Audio
;
2682 priv
->chains
[1]->pin_category
=&PIN_CATEGORY_CAPTURE
;
2683 priv
->chains
[2]->type
=vbi
;
2684 priv
->chains
[2]->majortype
=&MEDIATYPE_VBI
;
2685 priv
->chains
[2]->pin_category
=&PIN_CATEGORY_VBI
;
2688 hr
= CoCreateInstance((GUID
*) & CLSID_FilterGraph
, NULL
,
2689 CLSCTX_INPROC_SERVER
, &IID_IGraphBuilder
,
2690 (void **) &priv
->pGraph
);
2692 mp_msg(MSGT_TV
,MSGL_DBG2
, "tvi_dshow: CoCreateInstance(FilterGraph) call failed. Error:0x%x\n", (unsigned int)hr
);
2696 if (mp_msg_test(MSGT_TV
, MSGL_DBG2
)) {
2697 AddToRot((IUnknown
*) priv
->pGraph
, &(priv
->dwRegister
));
2700 hr
= CoCreateInstance((GUID
*) & CLSID_CaptureGraphBuilder2
, NULL
,
2701 CLSCTX_INPROC_SERVER
, &IID_ICaptureGraphBuilder2
,
2702 (void **) &priv
->pBuilder
);
2704 mp_msg(MSGT_TV
,MSGL_DBG2
, "tvi_dshow: CoCreateInstance(CaptureGraphBuilder) call failed. Error:0x%x\n", (unsigned int)hr
);
2708 hr
= OLE_CALL_ARGS(priv
->pBuilder
, SetFiltergraph
, priv
->pGraph
);
2710 mp_msg(MSGT_TV
,MSGL_ERR
, "tvi_dshow: SetFiltergraph call failed. Error:0x%x\n",(unsigned int)hr
);
2714 mp_msg(MSGT_TV
, MSGL_DBG2
, "tvi_dshow: Searching for available video capture devices\n");
2715 priv
->chains
[0]->pCaptureFilter
= find_capture_device(priv
->dev_index
, &CLSID_VideoInputDeviceCategory
);
2716 if(!priv
->chains
[0]->pCaptureFilter
){
2717 mp_tmsg(MSGT_TV
,MSGL_ERR
, "tvi_dshow: Unable to find video capture device\n");
2720 hr
= OLE_CALL_ARGS(priv
->pGraph
, AddFilter
, priv
->chains
[0]->pCaptureFilter
, NULL
);
2722 mp_msg(MSGT_TV
, MSGL_DBG2
, "tvi_dshow: Unable to add video capture device to Directshow graph. Error:0x%x\n", (unsigned int)hr
);
2725 mp_msg(MSGT_TV
, MSGL_DBG2
, "tvi_dshow: Searching for available audio capture devices\n");
2726 if (priv
->adev_index
!= -1) {
2727 priv
->chains
[1]->pCaptureFilter
= find_capture_device(priv
->adev_index
, &CLSID_AudioInputDeviceCategory
); //output available audio edevices
2728 if(!priv
->chains
[1]->pCaptureFilter
){
2729 mp_tmsg(MSGT_TV
,MSGL_ERR
, "tvi_dshow: Unable to find audio capture device\n");
2733 hr
= OLE_CALL_ARGS(priv
->pGraph
, AddFilter
, priv
->chains
[1]->pCaptureFilter
, NULL
);
2735 mp_msg(MSGT_TV
,MSGL_DBG2
, "tvi_dshow: Unable to add audio capture device to Directshow graph. Error:0x%x\n", (unsigned int)hr
);
2739 hr
= OLE_QUERYINTERFACE(priv
->chains
[0]->pCaptureFilter
, IID_IBaseFilter
, priv
->chains
[1]->pCaptureFilter
);
2741 /* increase refrence counter for capture filter ad store pointer into vbi chain structure too */
2742 hr
= OLE_QUERYINTERFACE(priv
->chains
[0]->pCaptureFilter
, IID_IBaseFilter
, priv
->chains
[2]->pCaptureFilter
);
2744 hr
= OLE_QUERYINTERFACE(priv
->chains
[0]->pCaptureFilter
, IID_IAMVideoProcAmp
,priv
->pVideoProcAmp
);
2745 if (FAILED(hr
) && hr
!= E_NOINTERFACE
)
2746 mp_msg(MSGT_TV
, MSGL_DBG2
, "tvi_dshow: Get IID_IAMVideoProcAmp failed (0x%x).\n", (unsigned int)hr
);
2749 mp_tmsg(MSGT_TV
, MSGL_INFO
, "tvi_dshow: Adjusting of brightness/hue/saturation/contrast is not supported by device\n");
2750 priv
->pVideoProcAmp
= NULL
;
2753 hr
= OLE_CALL_ARGS(priv
->pBuilder
, FindInterface
,
2754 &PIN_CATEGORY_CAPTURE
,
2755 priv
->chains
[0]->majortype
,
2756 priv
->chains
[0]->pCaptureFilter
,
2757 &IID_IAMCrossbar
, (void **) &(priv
->pCrossbar
));
2759 mp_tmsg(MSGT_TV
, MSGL_INFO
, "tvi_dshow: Selection of capture source is not supported by device\n");
2760 priv
->pCrossbar
= NULL
;
2763 if (priv
->tv_param
->amode
>= 0) {
2764 IAMTVAudio
*pTVAudio
;
2765 hr
= OLE_CALL_ARGS(priv
->pBuilder
, FindInterface
, NULL
, NULL
,priv
->chains
[0]->pCaptureFilter
,&IID_IAMTVAudio
, (void *) &pTVAudio
);
2767 switch (priv
->tv_param
->amode
) {
2769 hr
= OLE_CALL_ARGS(pTVAudio
, put_TVAudioMode
, AMTVAUDIO_MODE_MONO
);
2772 hr
= OLE_CALL_ARGS(pTVAudio
, put_TVAudioMode
, AMTVAUDIO_MODE_STEREO
);
2775 hr
= OLE_CALL_ARGS(pTVAudio
, put_TVAudioMode
,
2776 AMTVAUDIO_MODE_LANG_A
);
2779 hr
= OLE_CALL_ARGS(pTVAudio
, put_TVAudioMode
,
2780 AMTVAUDIO_MODE_LANG_B
);
2783 OLE_RELEASE_SAFE(pTVAudio
);
2785 mp_tmsg(MSGT_TV
, MSGL_WARN
, "tvi_dshow: Unable to set audio mode %d. Error:0x%x\n", priv
->tv_param
->amode
,(unsigned int)hr
);
2789 // Video chain initialization
2790 hr
= init_chain_common(priv
->pBuilder
, priv
->chains
[0]);
2795 Audio chain initialization
2796 Since absent audio stream is not fatal,
2797 at least one NULL pointer should be kept in format arrays
2798 (to avoid another additional check everywhere for array presence).
2800 hr
= init_chain_common(priv
->pBuilder
, priv
->chains
[1]);
2803 mp_msg(MSGT_TV
, MSGL_V
, "tvi_dshow: Unable to initialize audio chain (Error:0x%x). Audio disabled\n", (unsigned long)hr
);
2804 priv
->chains
[1]->arpmt
=calloc(1, sizeof(AM_MEDIA_TYPE
*));
2805 priv
->chains
[1]->arStreamCaps
=calloc(1, sizeof(void*));
2809 VBI chain initialization
2810 Since absent VBI stream is not fatal,
2811 at least one NULL pointer should be kept in format arrays
2812 (to avoid another additional check everywhere for array presence).
2814 hr
= init_chain_common(priv
->pBuilder
, priv
->chains
[2]);
2817 mp_msg(MSGT_TV
, MSGL_V
, "tvi_dshow: Unable to initialize VBI chain (Error:0x%x). Teletext disabled\n", (unsigned long)hr
);
2818 priv
->chains
[2]->arpmt
=calloc(1, sizeof(AM_MEDIA_TYPE
*));
2819 priv
->chains
[2]->arStreamCaps
=calloc(1, sizeof(void*));
2822 if (!priv
->chains
[0]->pStreamConfig
)
2823 mp_tmsg(MSGT_TV
, MSGL_INFO
, "tvi_dshow: Changing video width/height is not supported by device.\n");
2825 if (!priv
->chains
[0]->arpmt
[priv
->chains
[0]->nFormatUsed
]
2826 || !extract_video_format(priv
->chains
[0]->arpmt
[priv
->chains
[0]->nFormatUsed
],
2827 &(priv
->fcc
), &(priv
->width
),
2829 mp_tmsg(MSGT_TV
, MSGL_ERR
, "tvi_dshow: Unable to parse video format structure.\n");
2833 if (priv
->chains
[1]->arpmt
[priv
->chains
[1]->nFormatUsed
]) {
2834 if (!extract_audio_format(priv
->chains
[1]->pmt
, &(priv
->samplerate
), NULL
, NULL
)) {
2835 mp_tmsg(MSGT_TV
, MSGL_ERR
, "tvi_dshow: Unable to parse audio format structure.\n");
2836 DisplayMediaType("audio format failed",priv
->chains
[1]->arpmt
[priv
->chains
[1]->nFormatUsed
]);
2841 hr
= OLE_QUERYINTERFACE(priv
->pGraph
, IID_IMediaControl
,priv
->pMediaControl
);
2843 mp_tmsg(MSGT_TV
,MSGL_ERR
, "tvi_dshow: Unable to get IMediaControl interface. Error:0x%x\n",(unsigned int)hr
);
2846 hr
= OLE_CALL_ARGS(priv
->pBuilder
, FindInterface
,
2847 &PIN_CATEGORY_CAPTURE
, NULL
,
2848 priv
->chains
[0]->pCaptureFilter
,
2849 &IID_IAMTVTuner
, (void **) &(priv
->pTVTuner
));
2851 if (!priv
->pTVTuner
) {
2852 mp_msg(MSGT_TV
, MSGL_DBG2
, "tvi_dshow: Unable to access IAMTVTuner (0x%x)\n", (unsigned int)hr
);
2855 // shows Tuner capabilities
2856 get_capabilities(priv
);
2858 if (priv
->pTVTuner
) {
2859 hr
= OLE_CALL_ARGS(priv
->pTVTuner
, put_CountryCode
,
2860 chanlist2country(priv
->tv_param
->chanlist
));
2862 mp_msg(MSGT_TV
,MSGL_DBG2
, "tvi_dshow: Call to put_CountryCode failed. Error:0x%x\n",(unsigned int)hr
);
2865 hr
= OLE_CALL_ARGS(priv
->pTVTuner
, put_Mode
, AMTUNER_MODE_TV
);
2867 mp_msg(MSGT_TV
,MSGL_DBG2
, "tvi_dshow: Call to put_Mode failed. Error:0x%x\n",(unsigned int)hr
);
2871 hr
= OLE_CALL_ARGS(priv
->pTVTuner
, get_ConnectInput
, &lInput
);
2873 mp_msg(MSGT_TV
,MSGL_DBG2
, "tvi_dshow: Call to get_ConnectInput failed. Error:0x%x\n",(unsigned int)hr
);
2878 lTunerInput
= strstr(priv
->tv_param
->chanlist
, "cable") ? TunerInputCable
: TunerInputAntenna
;
2880 hr
= OLE_CALL_ARGS(priv
->pTVTuner
, put_InputType
, lInput
, lTunerInput
);
2882 mp_msg(MSGT_TV
,MSGL_DBG2
, "tvi_dshow: Call to put_InputType failed. Error:0x%x\n",(unsigned int)hr
);
2889 for VIVO cards we should check if preview pin is available on video capture device.
2890 If it is not, we have to connect Video Port Manager filter to VP pin of capture device filter.
2891 Otherwise we will get 0x8007001f (Device is not functioning properly) when attempting to start graph
2893 hr
= OLE_CALL_ARGS(priv
->pBuilder
, FindPin
,
2894 (IUnknown
*) priv
->chains
[0]->pCaptureFilter
,
2896 &PIN_CATEGORY_VIDEOPORT
, NULL
, FALSE
,
2897 0, (IPin
**) & pVPOutPin
);
2898 if (SUCCEEDED(hr
)) {
2899 hr
= OLE_CALL_ARGS(priv
->pGraph
, Render
, pVPOutPin
);
2900 OLE_RELEASE_SAFE(pVPOutPin
);
2903 mp_tmsg(MSGT_TV
,MSGL_ERR
, "tvi_dshow: Unable to terminate VideoPort pin with any filter in graph. Error:0x%x\n", (unsigned int)hr
);
2908 OLE_CALL_ARGS(priv
->pGraph
, EnumFilters
, &pEnum
);
2909 while (OLE_CALL_ARGS(pEnum
, Next
, 1, &pFilter
, NULL
) == S_OK
) {
2910 LPVIDEOWINDOW pVideoWindow
;
2911 hr
= OLE_QUERYINTERFACE(pFilter
, IID_IVideoWindow
, pVideoWindow
);
2914 if(priv
->tv_param
->hidden_vp_renderer
){
2915 OLE_CALL_ARGS(pVideoWindow
,put_Visible
,/* OAFALSE*/ 0);
2916 OLE_CALL_ARGS(pVideoWindow
,put_AutoShow
,/* OAFALSE*/ 0);
2919 OLE_CALL_ARGS(priv
->pGraph
, RemoveFilter
, pFilter
);
2921 OLE_RELEASE_SAFE(pVideoWindow
);
2923 OLE_RELEASE_SAFE(pFilter
);
2925 OLE_RELEASE_SAFE(pEnum
);
2926 if(priv
->tv_param
->system_clock
)
2928 LPREFERENCECLOCK rc
;
2930 hr
= CoCreateInstance((GUID
*) & CLSID_SystemClock
, NULL
,
2931 CLSCTX_INPROC_SERVER
, &IID_IReferenceClock
,
2934 OLE_QUERYINTERFACE(priv
->pBuilder
,IID_IBaseFilter
,pBF
);
2935 OLE_CALL_ARGS(pBF
,SetSyncSource
,rc
);
2937 if(vbi_get_props(priv
,&(priv
->tsp
))!=TVI_CONTROL_TRUE
)
2943 mp_tmsg(MSGT_TV
,MSGL_ERR
, "tvi_dshow: Directshow graph initialization failure.\n");
2950 * \brief chain uninitialization
2951 * \param chain chain data structure
2953 static void destroy_chain(chain_t
*chain
)
2960 OLE_RELEASE_SAFE(chain
->pStreamConfig
);
2961 OLE_RELEASE_SAFE(chain
->pCaptureFilter
);
2962 OLE_RELEASE_SAFE(chain
->pCSGCB
);
2963 OLE_RELEASE_SAFE(chain
->pCapturePin
);
2964 OLE_RELEASE_SAFE(chain
->pSGIn
);
2965 OLE_RELEASE_SAFE(chain
->pSG
);
2966 OLE_RELEASE_SAFE(chain
->pSGF
);
2969 DeleteMediaType(chain
->pmt
);
2972 for (i
= 0; chain
->arpmt
[i
]; i
++) {
2973 DeleteMediaType(chain
->arpmt
[i
]);
2978 if (chain
->arStreamCaps
) {
2979 for (i
= 0; chain
->arStreamCaps
[i
]; i
++) {
2980 free(chain
->arStreamCaps
[i
]);
2982 free(chain
->arStreamCaps
);
2986 destroy_ringbuffer(chain
->rbuf
);
2993 * \brief driver uninitialization
2995 * \param priv driver's private data structure
2999 static int uninit(priv_t
* priv
)
3005 if (priv
->dwRegister
) {
3006 RemoveFromRot(priv
->dwRegister
);
3008 teletext_control(priv
->priv_vbi
,TV_VBI_CONTROL_STOP
,(void*)1);
3009 //stop audio grabber thread
3011 if (priv
->state
&& priv
->pMediaControl
) {
3012 OLE_CALL(priv
->pMediaControl
, Stop
);
3014 OLE_RELEASE_SAFE(priv
->pMediaControl
);
3018 if (priv
->chains
[0]->pCaptureFilter
)
3019 OLE_CALL_ARGS(priv
->pGraph
, RemoveFilter
, priv
->chains
[0]->pCaptureFilter
);
3020 if (priv
->chains
[1]->pCaptureFilter
)
3021 OLE_CALL_ARGS(priv
->pGraph
, RemoveFilter
, priv
->chains
[1]->pCaptureFilter
);
3023 OLE_RELEASE_SAFE(priv
->pCrossbar
);
3024 OLE_RELEASE_SAFE(priv
->pVideoProcAmp
);
3025 OLE_RELEASE_SAFE(priv
->pGraph
);
3026 OLE_RELEASE_SAFE(priv
->pBuilder
);
3027 if(priv
->freq_table
){
3028 priv
->freq_table_len
=-1;
3029 free(priv
->freq_table
);
3030 priv
->freq_table
=NULL
;
3035 destroy_chain(priv
->chains
[i
]);
3036 priv
->chains
[i
] = NULL
;
3043 * \brief driver pre-initialization
3045 * \param device string, containing device name in form "x[.y]", where x is video capture device
3046 * (default: 0, first available); y (if given) sets audio capture device
3048 * \return 1 if success,0 - otherwise
3050 static tvi_handle_t
*tvi_init_dshow(tv_param_t
* tv_param
)
3056 h
= tv_new_handle(sizeof(priv_t
), &functions
);
3062 memset(priv
, 0, sizeof(priv_t
));
3063 priv
->direct_setfreq_call
= 1; //first using direct call. if it fails, workaround will be enabled
3064 priv
->direct_getfreq_call
= 1; //first using direct call. if it fails, workaround will be enabled
3065 priv
->adev_index
= -1;
3066 priv
->freq_table_len
=-1;
3067 priv
->tv_param
=tv_param
;
3069 if (tv_param
->device
) {
3070 if (sscanf(tv_param
->device
, "%d", &a
) == 1) {
3071 priv
->dev_index
= a
;
3073 mp_tmsg(MSGT_TV
, MSGL_ERR
, "tvi_dshow: Wrong device parameter: %s\n", tv_param
->device
);
3077 if (priv
->dev_index
< 0) {
3078 mp_tmsg(MSGT_TV
, MSGL_ERR
, "tvi_dshow: Wrong device index: %d\n", a
);
3083 if (tv_param
->adevice
) {
3084 if (sscanf(tv_param
->adevice
, "%d", &a
) == 1) {
3085 priv
->adev_index
= a
;
3087 mp_tmsg(MSGT_TV
, MSGL_ERR
, "tvi_dshow: Wrong adevice parameter: %s\n", tv_param
->adevice
);
3091 if (priv
->dev_index
< 0) {
3092 mp_tmsg(MSGT_TV
, MSGL_ERR
, "tvi_dshow: Wrong adevice index: %d\n", a
);
3101 * \brief driver's ioctl handler
3103 * \param priv driver's private data structure
3104 * \param cmd ioctl command
3105 * \param arg ioct command's parameter
3107 * \return TVI_CONTROL_TRUE if success
3108 * \return TVI_CONTROL_FALSE if failure
3109 * \return TVI_CONTROL_UNKNOWN if unknowm cmd called
3111 static int control(priv_t
* priv
, int cmd
, void *arg
)
3115 case TVI_CONTROL_VID_SET_FORMAT
:
3119 int result
= TVI_CONTROL_TRUE
;
3122 return TVI_CONTROL_FALSE
;
3125 if(!priv
->chains
[0]->arpmt
)
3126 return TVI_CONTROL_FALSE
;
3127 for (i
= 0; priv
->chains
[0]->arpmt
[i
]; i
++)
3128 if (check_video_format
3129 (priv
->chains
[0]->arpmt
[i
], fcc
, priv
->width
, priv
->height
))
3131 if (!priv
->chains
[0]->arpmt
[i
])
3134 VIDEOINFOHEADER
* Vhdr
= NULL
;
3137 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
));
3139 if (priv
->chains
[0]->arpmt
[0])
3140 Vhdr
= (VIDEOINFOHEADER
*) priv
->chains
[0]->arpmt
[0]->pbFormat
;
3142 if(Vhdr
&& Vhdr
->bmiHeader
.biSizeImage
)
3143 fps
= Vhdr
->dwBitRate
/ (8 * Vhdr
->bmiHeader
.biSizeImage
);
3145 pmt
=create_video_format(fcc
, priv
->width
, priv
->height
, fps
);
3148 mp_msg(MSGT_TV
, MSGL_V
, "tvi_dshow: Unable to create AM_MEDIA_TYPE structure for given format\n");
3149 return TVI_CONTROL_FALSE
;
3151 priv
->chains
[0]->arpmt
=realloc(priv
->chains
[0]->arpmt
, (i
+2)*sizeof(AM_MEDIA_TYPE
*));
3152 priv
->chains
[0]->arpmt
[i
+1] = NULL
;
3153 priv
->chains
[0]->arpmt
[i
] = pmt
;
3155 priv
->chains
[0]->arStreamCaps
=realloc(priv
->chains
[0]->arStreamCaps
, (i
+2)*sizeof(void*));
3156 priv
->chains
[0]->arpmt
[i
+1] = NULL
;
3158 result
= TVI_CONTROL_FALSE
;
3162 tmp
=priv
->chains
[0]->arpmt
[i
];
3163 tmp2
=priv
->chains
[0]->arStreamCaps
[i
];
3166 priv
->chains
[0]->arpmt
[j
] = priv
->chains
[0]->arpmt
[j
-1];
3167 priv
->chains
[0]->arStreamCaps
[j
] = priv
->chains
[0]->arStreamCaps
[j
-1];
3169 priv
->chains
[0]->arpmt
[0] = tmp
;
3170 priv
->chains
[0]->arStreamCaps
[0] = tmp2
;
3172 priv
->chains
[0]->nFormatUsed
= 0;
3174 if (priv
->chains
[0]->pmt
)
3175 DeleteMediaType(priv
->chains
[0]->pmt
);
3176 priv
->chains
[0]->pmt
=
3177 CreateMediaType(priv
->chains
[0]->arpmt
[priv
->chains
[0]->nFormatUsed
]);
3178 DisplayMediaType("VID_SET_FORMAT", priv
->chains
[0]->pmt
);
3180 Setting width & height to preferred by driver values
3182 extract_video_format(priv
->chains
[0]->arpmt
[priv
->chains
[0]->nFormatUsed
],
3183 &(priv
->fcc
), &(priv
->width
),
3187 case TVI_CONTROL_VID_GET_FORMAT
:
3189 if(!priv
->chains
[0]->pmt
)
3190 return TVI_CONTROL_FALSE
;
3192 Build video chain (for video format negotiation).
3193 If this was done before, routine will do nothing.
3195 build_video_chain(priv
);
3196 DisplayMediaType("VID_GET_FORMAT", priv
->chains
[0]->pmt
);
3198 *(int *) arg
= priv
->fcc
;
3199 return TVI_CONTROL_TRUE
;
3201 return TVI_CONTROL_FALSE
;
3203 case TVI_CONTROL_VID_SET_WIDTH
:
3205 VIDEO_STREAM_CONFIG_CAPS
*pCaps
;
3206 VIDEOINFOHEADER
*Vhdr
;
3207 int width
= *(int *) arg
;
3209 return TVI_CONTROL_FALSE
;
3211 pCaps
= priv
->chains
[0]->arStreamCaps
[priv
->chains
[0]->nFormatUsed
];
3213 return TVI_CONTROL_FALSE
;
3214 if (width
< pCaps
->MinOutputSize
.cx
3215 || width
> pCaps
->MaxOutputSize
.cx
)
3216 return TVI_CONTROL_FALSE
;
3218 if (width
% pCaps
->OutputGranularityX
)
3219 return TVI_CONTROL_FALSE
;
3221 if (!priv
->chains
[0]->pmt
|| !priv
->chains
[0]->pmt
->pbFormat
)
3222 return TVI_CONTROL_FALSE
;
3223 Vhdr
= (VIDEOINFOHEADER
*) priv
->chains
[0]->pmt
->pbFormat
;
3224 Vhdr
->bmiHeader
.biWidth
= width
;
3225 priv
->chains
[0]->pmt
->lSampleSize
= Vhdr
->bmiHeader
.biSizeImage
=
3226 labs(Vhdr
->bmiHeader
.biBitCount
* Vhdr
->bmiHeader
.biWidth
*
3227 Vhdr
->bmiHeader
.biHeight
) >> 3;
3229 priv
->width
= width
;
3231 return TVI_CONTROL_TRUE
;
3233 case TVI_CONTROL_VID_GET_WIDTH
:
3236 *(int *) arg
= priv
->width
;
3237 return TVI_CONTROL_TRUE
;
3239 return TVI_CONTROL_FALSE
;
3241 case TVI_CONTROL_VID_CHK_WIDTH
:
3243 VIDEO_STREAM_CONFIG_CAPS
*pCaps
;
3244 int width
= *(int *) arg
;
3245 pCaps
= priv
->chains
[0]->arStreamCaps
[priv
->chains
[0]->nFormatUsed
];
3247 return TVI_CONTROL_FALSE
;
3248 if (width
< pCaps
->MinOutputSize
.cx
3249 || width
> pCaps
->MaxOutputSize
.cx
)
3250 return TVI_CONTROL_FALSE
;
3252 if (width
% pCaps
->OutputGranularityX
)
3253 return TVI_CONTROL_FALSE
;
3254 return TVI_CONTROL_TRUE
;
3256 case TVI_CONTROL_VID_SET_HEIGHT
:
3258 VIDEO_STREAM_CONFIG_CAPS
*pCaps
;
3259 VIDEOINFOHEADER
*Vhdr
;
3260 int height
= *(int *) arg
;
3262 return TVI_CONTROL_FALSE
;
3264 pCaps
= priv
->chains
[0]->arStreamCaps
[priv
->chains
[0]->nFormatUsed
];
3266 return TVI_CONTROL_FALSE
;
3267 if (height
< pCaps
->MinOutputSize
.cy
3268 || height
> pCaps
->MaxOutputSize
.cy
)
3269 return TVI_CONTROL_FALSE
;
3271 if (height
% pCaps
->OutputGranularityY
)
3272 return TVI_CONTROL_FALSE
;
3274 if (!priv
->chains
[0]->pmt
|| !priv
->chains
[0]->pmt
->pbFormat
)
3275 return TVI_CONTROL_FALSE
;
3276 Vhdr
= (VIDEOINFOHEADER
*) priv
->chains
[0]->pmt
->pbFormat
;
3278 if (Vhdr
->bmiHeader
.biHeight
< 0)
3279 Vhdr
->bmiHeader
.biHeight
= -height
;
3281 Vhdr
->bmiHeader
.biHeight
= height
;
3282 priv
->chains
[0]->pmt
->lSampleSize
= Vhdr
->bmiHeader
.biSizeImage
=
3283 labs(Vhdr
->bmiHeader
.biBitCount
* Vhdr
->bmiHeader
.biWidth
*
3284 Vhdr
->bmiHeader
.biHeight
) >> 3;
3286 priv
->height
= height
;
3287 return TVI_CONTROL_TRUE
;
3289 case TVI_CONTROL_VID_GET_HEIGHT
:
3292 *(int *) arg
= priv
->height
;
3293 return TVI_CONTROL_TRUE
;
3295 return TVI_CONTROL_FALSE
;
3297 case TVI_CONTROL_VID_CHK_HEIGHT
:
3299 VIDEO_STREAM_CONFIG_CAPS
*pCaps
;
3300 int height
= *(int *) arg
;
3301 pCaps
= priv
->chains
[0]->arStreamCaps
[priv
->chains
[0]->nFormatUsed
];
3303 return TVI_CONTROL_FALSE
;
3304 if (height
< pCaps
->MinOutputSize
.cy
3305 || height
> pCaps
->MaxOutputSize
.cy
)
3306 return TVI_CONTROL_FALSE
;
3308 if (height
% pCaps
->OutputGranularityY
)
3309 return TVI_CONTROL_FALSE
;
3311 return TVI_CONTROL_TRUE
;
3313 case TVI_CONTROL_IS_AUDIO
:
3314 if (!priv
->chains
[1]->pmt
)
3315 return TVI_CONTROL_FALSE
;
3317 return TVI_CONTROL_TRUE
;
3318 case TVI_CONTROL_IS_VIDEO
:
3319 return TVI_CONTROL_TRUE
;
3320 case TVI_CONTROL_AUD_GET_FORMAT
:
3322 *(int *) arg
= AF_FORMAT_S16_LE
;
3323 if (!priv
->chains
[1]->pmt
)
3324 return TVI_CONTROL_FALSE
;
3326 return TVI_CONTROL_TRUE
;
3328 case TVI_CONTROL_AUD_GET_CHANNELS
:
3330 *(int *) arg
= priv
->channels
;
3331 if (!priv
->chains
[1]->pmt
)
3332 return TVI_CONTROL_FALSE
;
3334 return TVI_CONTROL_TRUE
;
3336 case TVI_CONTROL_AUD_SET_SAMPLERATE
:
3340 return TVI_CONTROL_FALSE
;
3341 if (!priv
->chains
[1]->arpmt
[0])
3342 return TVI_CONTROL_FALSE
;
3344 samplerate
= *(int *) arg
;
3346 for (i
= 0; priv
->chains
[1]->arpmt
[i
]; i
++)
3347 if (check_audio_format
3348 (priv
->chains
[1]->arpmt
[i
], samplerate
, 16, priv
->channels
))
3350 if (!priv
->chains
[1]->arpmt
[i
]) {
3351 //request not found. failing back to first available
3352 mp_tmsg(MSGT_TV
, MSGL_WARN
, "tvi_dshow: Samplerate %d is not supported by device. Failing back to first available.\n", samplerate
);
3355 if (priv
->chains
[1]->pmt
)
3356 DeleteMediaType(priv
->chains
[1]->pmt
);
3357 priv
->chains
[1]->pmt
= CreateMediaType(priv
->chains
[1]->arpmt
[i
]);
3358 extract_audio_format(priv
->chains
[1]->arpmt
[i
], &(priv
->samplerate
),
3359 NULL
, &(priv
->channels
));
3360 return TVI_CONTROL_TRUE
;
3362 case TVI_CONTROL_AUD_GET_SAMPLERATE
:
3364 *(int *) arg
= priv
->samplerate
;
3365 if (!priv
->samplerate
)
3366 return TVI_CONTROL_FALSE
;
3367 if (!priv
->chains
[1]->pmt
)
3368 return TVI_CONTROL_FALSE
;
3370 return TVI_CONTROL_TRUE
;
3372 case TVI_CONTROL_AUD_GET_SAMPLESIZE
:
3375 if (!priv
->chains
[1]->pmt
)
3376 return TVI_CONTROL_FALSE
;
3377 if (!priv
->chains
[1]->pmt
->pbFormat
)
3378 return TVI_CONTROL_FALSE
;
3379 pWF
= (WAVEFORMATEX
*) priv
->chains
[1]->pmt
->pbFormat
;
3380 *(int *) arg
= pWF
->wBitsPerSample
/ 8;
3381 return TVI_CONTROL_TRUE
;
3383 case TVI_CONTROL_IS_TUNER
:
3385 if (!priv
->pTVTuner
)
3386 return TVI_CONTROL_FALSE
;
3388 return TVI_CONTROL_TRUE
;
3390 case TVI_CONTROL_TUN_SET_NORM
:
3392 IAMAnalogVideoDecoder
*pVD
;
3399 if (i
< 0 || i
>= tv_available_norms_count
)
3400 return TVI_CONTROL_FALSE
;
3401 lAnalogFormat
= tv_norms
[tv_available_norms
[i
]].index
;
3403 hr
= OLE_QUERYINTERFACE(priv
->chains
[0]->pCaptureFilter
,IID_IAMAnalogVideoDecoder
, pVD
);
3405 return TVI_CONTROL_FALSE
;
3406 hr
= OLE_CALL_ARGS(pVD
, put_TVFormat
, lAnalogFormat
);
3407 OLE_RELEASE_SAFE(pVD
);
3409 return TVI_CONTROL_FALSE
;
3411 return TVI_CONTROL_TRUE
;
3413 case TVI_CONTROL_TUN_GET_NORM
:
3418 IAMAnalogVideoDecoder
*pVD
;
3420 hr
= OLE_QUERYINTERFACE(priv
->chains
[0]->pCaptureFilter
,IID_IAMAnalogVideoDecoder
, pVD
);
3422 hr
= OLE_CALL_ARGS(pVD
, get_TVFormat
, &lAnalogFormat
);
3423 OLE_RELEASE_SAFE(pVD
);
3426 if (FAILED(hr
)) { //trying another method
3427 if (!priv
->pTVTuner
)
3428 return TVI_CONTROL_FALSE
;
3429 hr
=OLE_CALL_ARGS(priv
->pTVTuner
, get_TVFormat
, &lAnalogFormat
);
3431 return TVI_CONTROL_FALSE
;
3433 for (i
= 0; i
< tv_available_norms_count
; i
++) {
3434 if (tv_norms
[tv_available_norms
[i
]].index
== lAnalogFormat
) {
3435 *(int *) arg
= i
+ 1;
3436 return TVI_CONTROL_TRUE
;
3439 return TVI_CONTROL_FALSE
;
3441 case TVI_CONTROL_SPC_GET_NORMID
:
3444 if (!priv
->pTVTuner
)
3445 return TVI_CONTROL_FALSE
;
3446 for (i
= 0; i
< tv_available_norms_count
; i
++) {
3448 (tv_norms
[tv_available_norms
[i
]].name
, (char *) arg
)) {
3449 *(int *) arg
= i
+ 1;
3450 return TVI_CONTROL_TRUE
;
3453 return TVI_CONTROL_FALSE
;
3455 case TVI_CONTROL_SPC_SET_INPUT
:
3457 return set_crossbar_input(priv
, *(int *) arg
);
3459 case TVI_CONTROL_TUN_GET_FREQ
:
3461 unsigned long lFreq
;
3463 if (!priv
->pTVTuner
)
3464 return TVI_CONTROL_FALSE
;
3466 ret
= get_frequency(priv
, &lFreq
);
3467 lFreq
= lFreq
/ (1000000/16); //convert from Hz to 1/16 MHz units
3469 *(unsigned long *) arg
= lFreq
;
3472 case TVI_CONTROL_TUN_SET_FREQ
:
3474 unsigned long nFreq
= *(unsigned long *) arg
;
3475 if (!priv
->pTVTuner
)
3476 return TVI_CONTROL_FALSE
;
3478 nFreq
= (1000000/16) * nFreq
; //convert from 1/16 MHz units to Hz
3479 return set_frequency(priv
, nFreq
);
3481 case TVI_CONTROL_VID_SET_HUE
:
3482 return set_control(priv
, VideoProcAmp_Hue
, *(int *) arg
);
3483 case TVI_CONTROL_VID_GET_HUE
:
3484 return get_control(priv
, VideoProcAmp_Hue
, (int *) arg
);
3485 case TVI_CONTROL_VID_SET_CONTRAST
:
3486 return set_control(priv
, VideoProcAmp_Contrast
, *(int *) arg
);
3487 case TVI_CONTROL_VID_GET_CONTRAST
:
3488 return get_control(priv
, VideoProcAmp_Contrast
, (int *) arg
);
3489 case TVI_CONTROL_VID_SET_SATURATION
:
3490 return set_control(priv
, VideoProcAmp_Saturation
, *(int *) arg
);
3491 case TVI_CONTROL_VID_GET_SATURATION
:
3492 return get_control(priv
, VideoProcAmp_Saturation
, (int *) arg
);
3493 case TVI_CONTROL_VID_SET_BRIGHTNESS
:
3494 return set_control(priv
, VideoProcAmp_Brightness
, *(int *) arg
);
3495 case TVI_CONTROL_VID_GET_BRIGHTNESS
:
3496 return get_control(priv
, VideoProcAmp_Brightness
, (int *) arg
);
3498 case TVI_CONTROL_VID_GET_FPS
:
3500 VIDEOINFOHEADER
*Vhdr
;
3501 if (!priv
->chains
[0]->pmt
)
3502 return TVI_CONTROL_FALSE
;
3503 if (!priv
->chains
[0]->pmt
->pbFormat
)
3504 return TVI_CONTROL_FALSE
;
3505 Vhdr
= (VIDEOINFOHEADER
*) priv
->chains
[0]->pmt
->pbFormat
;
3507 (1.0 * Vhdr
->dwBitRate
) / (Vhdr
->bmiHeader
.biSizeImage
* 8);
3508 return TVI_CONTROL_TRUE
;
3510 case TVI_CONTROL_IMMEDIATE
:
3511 priv
->immediate_mode
= 1;
3512 return TVI_CONTROL_TRUE
;
3513 case TVI_CONTROL_VBI_INIT
:
3517 if(teletext_control(NULL
,TV_VBI_CONTROL_START
,&ptr
)==VBI_CONTROL_TRUE
)
3520 priv
->priv_vbi
=NULL
;
3521 return TVI_CONTROL_TRUE
;
3523 case TVI_CONTROL_GET_VBI_PTR
:
3524 *(void **)arg
=priv
->priv_vbi
;
3525 return TVI_CONTROL_TRUE
;
3527 return TVI_CONTROL_UNKNOWN
;