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 static void set_buffer_preference(int nDiv
, WAVEFORMATEX
*pWF
,
509 IPin
*pOutPin
, IPin
*pInPin
)
511 ALLOCATOR_PROPERTIES prop
;
512 IAMBufferNegotiation
* pBN
;
516 prop
.cbBuffer
= pWF
->nAvgBytesPerSec
/nDiv
;
519 prop
.cbBuffer
+= pWF
->nBlockAlign
- 1;
520 prop
.cbBuffer
-= prop
.cbBuffer
% pWF
->nBlockAlign
;
524 hr
=OLE_QUERYINTERFACE(pOutPin
,IID_IAMBufferNegotiation
,pBN
);
526 mp_msg(MSGT_TV
,MSGL_DBG2
,"tvi_dshow: pOutPin->QueryInterface(IID_IAMBufferNegotiation) Error: 0x%x\n",(unsigned int)hr
);
528 hr
=OLE_CALL_ARGS(pBN
,SuggestAllocatorProperties
,&prop
);
530 mp_msg(MSGT_TV
,MSGL_DBG2
,"tvi_dshow:pOutPin->SuggestAllocatorProperties Error:0x%x\n",(unsigned int)hr
);
531 OLE_RELEASE_SAFE(pBN
);
533 hr
=OLE_QUERYINTERFACE(pInPin
,IID_IAMBufferNegotiation
,pBN
);
535 mp_msg(MSGT_TV
,MSGL_DBG2
,"tvi_dshow: pInPin->QueryInterface(IID_IAMBufferNegotiation) Error: 0x%x",(unsigned int)hr
);
537 hr
=OLE_CALL_ARGS(pBN
,SuggestAllocatorProperties
,&prop
);
539 mp_msg(MSGT_TV
,MSGL_DBG2
,"tvi_dshow: pInPit->SuggestAllocatorProperties Error:0x%x\n",(unsigned int)hr
);
540 OLE_RELEASE_SAFE(pBN
);
544 *---------------------------------------------------------------------------------------
546 * CSampleGrabberCD class. Used for receiving samples from DirectShow.
548 *---------------------------------------------------------------------------------------
550 /// CSampleGrabberCD destructor
551 static void CSampleGrabberCB_Destroy(CSampleGrabberCB
* This
)
557 /// CSampleGrabberCD IUnknown interface methods implementation
558 static long STDCALL
CSampleGrabberCB_QueryInterface(ISampleGrabberCB
*
563 CSampleGrabberCB
*me
= (CSampleGrabberCB
*) This
;
566 Debug
printf("CSampleGrabberCB_QueryInterface(%p) called\n", This
);
569 for (r
= me
->interfaces
;
570 i
< sizeof(me
->interfaces
) / sizeof(me
->interfaces
[0]); r
++, i
++)
571 if (!memcmp(r
, riid
, sizeof(*r
))) {
572 OLE_CALL(This
, AddRef
);
576 Debug
printf("Query failed! (GUID: 0x%x)\n", *(unsigned int *) riid
);
577 return E_NOINTERFACE
;
580 static long STDCALL
CSampleGrabberCB_AddRef(ISampleGrabberCB
* This
)
582 CSampleGrabberCB
*me
= (CSampleGrabberCB
*) This
;
583 Debug
printf("CSampleGrabberCB_AddRef(%p) called (ref:%d)\n", This
,
585 return ++(me
->refcount
);
588 static long STDCALL
CSampleGrabberCB_Release(ISampleGrabberCB
* This
)
590 CSampleGrabberCB
*me
= (CSampleGrabberCB
*) This
;
591 Debug
printf("CSampleGrabberCB_Release(%p) called (new ref:%d)\n",
592 This
, me
->refcount
- 1);
593 if (--(me
->refcount
) == 0)
594 CSampleGrabberCB_Destroy(me
);
599 static HRESULT STDCALL
CSampleGrabberCB_BufferCB(ISampleGrabberCB
*This
,
604 CSampleGrabberCB
*this = (CSampleGrabberCB
*) This
;
605 grabber_ringbuffer_t
*rb
= this->pbuf
;
610 if (!rb
->ringbuffer
) {
611 rb
->buffersize
/= lBufferLen
;
612 if (init_ringbuffer(rb
, rb
->buffersize
, lBufferLen
) != S_OK
)
615 mp_msg(MSGT_TV
, MSGL_DBG4
,
616 "tvi_dshow: BufferCB(%p): len=%ld ts=%f\n", This
, lBufferLen
, SampleTime
);
617 EnterCriticalSection(rb
->pMutex
);
618 if (rb
->count
>= rb
->buffersize
) {
619 rb
->head
= (rb
->head
+ 1) % rb
->buffersize
;
623 memcpy(rb
->ringbuffer
[rb
->tail
], pBuffer
,
624 lBufferLen
< rb
->blocksize
? lBufferLen
: rb
->blocksize
);
625 rb
->dpts
[rb
->tail
] = SampleTime
;
626 rb
->tail
= (rb
->tail
+ 1) % rb
->buffersize
;
628 LeaveCriticalSection(rb
->pMutex
);
633 /// wrapper. directshow does the same when BufferCB callback is requested
634 static HRESULT STDCALL
CSampleGrabberCB_SampleCB(ISampleGrabberCB
*This
,
636 LPMEDIASAMPLE pSample
)
640 long long tStart
,tEnd
;
642 grabber_ringbuffer_t
*rb
= ((CSampleGrabberCB
*)This
)->pbuf
;
644 len
=OLE_CALL(pSample
,GetSize
);
646 hr
=OLE_CALL_ARGS(pSample
,GetTime
,&tStart
,&tEnd
);
650 mp_msg(MSGT_TV
, MSGL_DBG4
,"tvi_dshow: SampleCB(%p): %d/%d %f\n", This
,rb
->count
,rb
->buffersize
,1e-7*tStart
);
651 hr
=OLE_CALL_ARGS(pSample
,GetPointer
,(void*)&buf
);
655 hr
=CSampleGrabberCB_BufferCB(This
,1e-7*tStart
,buf
,len
);
660 /// main grabbing routine
661 static CSampleGrabberCB
*CSampleGrabberCB_Create(grabber_ringbuffer_t
*
664 CSampleGrabberCB
*This
= malloc(sizeof(CSampleGrabberCB
));
668 This
->lpVtbl
= malloc(sizeof(ISampleGrabberVtbl
));
670 CSampleGrabberCB_Destroy(This
);
674 This
->lpVtbl
->QueryInterface
= CSampleGrabberCB_QueryInterface
;
675 This
->lpVtbl
->AddRef
= CSampleGrabberCB_AddRef
;
676 This
->lpVtbl
->Release
= CSampleGrabberCB_Release
;
677 This
->lpVtbl
->SampleCB
= CSampleGrabberCB_SampleCB
;
678 This
->lpVtbl
->BufferCB
= CSampleGrabberCB_BufferCB
;
680 This
->interfaces
[0] = IID_IUnknown
;
681 This
->interfaces
[1] = IID_ISampleGrabberCB
;
689 *---------------------------------------------------------------------------------------
691 * ROT related methods (register, unregister)
693 *---------------------------------------------------------------------------------------
696 Registering graph in ROT. User will be able to connect to graph from GraphEdit.
698 static HRESULT
AddToRot(IUnknown
* pUnkGraph
, DWORD
* pdwRegister
)
701 IRunningObjectTable
*pROT
;
705 if (FAILED(GetRunningObjectTable(0, &pROT
))) {
708 wsprintfW(wsz
, L
"FilterGraph %08x pid %08x", (DWORD_PTR
) pUnkGraph
,
709 GetCurrentProcessId());
710 hr
= CreateItemMoniker(L
"!", wsz
, &pMoniker
);
712 hr
= OLE_CALL_ARGS(pROT
, Register
, ROTFLAGS_REGISTRATIONKEEPSALIVE
,
713 pUnkGraph
, pMoniker
, pdwRegister
);
714 OLE_RELEASE_SAFE(pMoniker
);
716 OLE_RELEASE_SAFE(pROT
);
720 /// Unregistering graph in ROT
721 static void RemoveFromRot(DWORD dwRegister
)
723 IRunningObjectTable
*pROT
;
724 if (SUCCEEDED(GetRunningObjectTable(0, &pROT
))) {
725 OLE_CALL_ARGS(pROT
, Revoke
, dwRegister
);
726 OLE_RELEASE_SAFE(pROT
);
731 *---------------------------------------------------------------------------------------
733 * ringbuffer related methods (init, destroy)
735 *---------------------------------------------------------------------------------------
738 * \brief ringbuffer destroying routine
740 * \param rb pointer to empty (just allocated) ringbuffer structure
742 * \note routine does not frees memory, allocated for grabber_rinbuffer_s structure
744 static void destroy_ringbuffer(grabber_ringbuffer_t
* rb
)
751 if (rb
->ringbuffer
) {
752 for (i
= 0; i
< rb
->buffersize
; i
++)
753 free(rb
->ringbuffer
[i
]);
754 free(rb
->ringbuffer
);
755 rb
->ringbuffer
= NULL
;
760 DeleteCriticalSection(rb
->pMutex
);
773 * \brief ringbuffer initialization
775 * \param rb pointer to empty (just allocated) ringbuffer structure
776 * \param buffersize size of buffer in blocks
777 * \param blocksize size of buffer's block
779 * \return S_OK if success
780 * \return E_OUTOFMEMORY not enough memory
782 * \note routine does not allocates memory for grabber_rinbuffer_s structure
784 static HRESULT
init_ringbuffer(grabber_ringbuffer_t
* rb
, int buffersize
,
790 return E_OUTOFMEMORY
;
792 rb
->buffersize
= buffersize
< 2 ? 2 : buffersize
;
793 rb
->blocksize
= blocksize
;
795 mp_msg(MSGT_TV
, MSGL_DBG2
, "tvi_dshow: Capture buffer: %d blocks of %d bytes.\n",
796 rb
->buffersize
, rb
->blocksize
);
798 rb
->ringbuffer
= malloc(rb
->buffersize
* sizeof(char *));
801 memset(rb
->ringbuffer
, 0, rb
->buffersize
* sizeof(char *));
803 for (i
= 0; i
< rb
->buffersize
; i
++) {
804 rb
->ringbuffer
[i
] = malloc(rb
->blocksize
* sizeof(char));
805 if (!rb
->ringbuffer
[i
]) {
806 destroy_ringbuffer(rb
);
807 return E_OUTOFMEMORY
;
810 rb
->dpts
= malloc(rb
->buffersize
* sizeof(double));
812 destroy_ringbuffer(rb
);
813 return E_OUTOFMEMORY
;
819 rb
->pMutex
= malloc(sizeof(CRITICAL_SECTION
));
821 destroy_ringbuffer(rb
);
822 return E_OUTOFMEMORY
;
824 InitializeCriticalSection(rb
->pMutex
);
829 *---------------------------------------------------------------------------------------
831 * Tuner related methods (frequency, capabilities, etc
833 *---------------------------------------------------------------------------------------
836 * \brief returns string with name for givend PsysCon_* constant
838 * \param lPhysicalType constant from PhysicalConnectorType enumeration
840 * \return pointer to string with apropriate name
843 * Caller should not free returned pointer
845 static char *physcon2str(const long lPhysicalType
)
848 for(i
=0; tv_physcon_types
[i
].name
; i
++)
849 if(tv_physcon_types
[i
].type
==lPhysicalType
)
850 return tv_physcon_types
[i
].name
;
855 * \brief converts MPlayer's chanlist to system country code.
857 * \param chanlist MPlayer's chanlist name
859 * \return system country code
862 * After call to IAMTVTuner::put_CountryCode with returned value tuner switches to frequency table used in specified
863 * country (which is usually larger then MPlayer's one, so workaround will work fine).
866 * Resolve trouble with cable channels (DirectShow's tuners must be switched between broadcast and cable channels modes.
868 static int chanlist2country(char *chanlist
)
871 for(i
=0; tv_chanlist2country
[i
].chanlist_name
; i
++)
872 if (!strcmp(chanlist
, tv_chanlist2country
[i
].chanlist_name
))
874 return tv_chanlist2country
[i
].country_code
;
878 * \brief loads specified resource from module and return pointer to it
880 * \param hDLL valid module desriptor
881 * \param index index of resource. resource with name "#<index>" will be loaded
883 * \return pointer to loader resource or NULL if error occured
885 static void *GetRC(HMODULE hDLL
, int index
)
892 snprintf(szRCDATA
, 10, "#%d", (int)RT_RCDATA
);
893 snprintf(szName
, 10, "#%d", index
);
895 hRes
= FindResource(hDLL
, szName
, szRCDATA
);
899 hTable
= LoadResource(hDLL
, hRes
);
903 return LockResource(hTable
);
907 * \brief loads frequency table for given country from kstvtune.ax
909 * \param[in] nCountry - country code
910 * \param[in] nInputType (TunerInputCable or TunerInputAntenna)
911 * \param[out] pplFreqTable - address of variable that receives pointer to array, containing frequencies
912 * \param[out] pnLen length of array
913 * \param[out] pnFirst - channel number of first entry in array (nChannelMax)
915 * \return S_OK if success
916 * \return E_POINTER pplFreqTable==NULL || plFirst==NULL || pnLen==NULL
917 * \return E_FAIL error occured during load
920 * - array must be freed by caller
921 * - MSDN says that it is not neccessery to unlock or free resource. It will be done after unloading DLL
923 static HRESULT
load_freq_table(int nCountry
, int nInputType
,
924 long **pplFreqTable
, int *pnLen
,
929 TRCCountryList
*pCountryList
;
932 mp_msg(MSGT_TV
, MSGL_DBG4
, "tvi_dshow: load_freq_table called %d (%s)\n",nCountry
,nInputType
== TunerInputAntenna
? "broadcast" : "cable");
933 /* ASSERT(sizeof(TRCCountryList)==10); // need properly aligned structure */
935 if (!pplFreqTable
|| !pnFirst
|| !pnLen
)
940 hDLL
= LoadLibrary("kstvtune.ax");
944 pCountryList
= GetRC(hDLL
, 9999);
949 for (i
= 0; pCountryList
[i
].CountryCode
!= 0; i
++)
950 if (pCountryList
[i
].CountryCode
== nCountry
)
952 if (pCountryList
[i
].CountryCode
== 0) {
956 if (nInputType
== TunerInputCable
)
957 index
= pCountryList
[i
].CableFreqTable
;
959 index
= pCountryList
[i
].BroadcastFreqTable
;
961 plFreqTable
= GetRC(hDLL
, index
); //First element is number of first channel, second - number of last channel
966 *pnFirst
= plFreqTable
[0];
967 *pnLen
= (int) (plFreqTable
[1] - plFreqTable
[0] + 1);
968 *pplFreqTable
= malloc((*pnLen
) * sizeof(long));
969 if (!*pplFreqTable
) {
973 for (i
= 0; i
< *pnLen
; i
++) {
974 (*pplFreqTable
)[i
] = plFreqTable
[i
+ 2];
975 mp_msg(MSGT_TV
, MSGL_DBG4
, "tvi_dshow: load_freq_table #%d => (%ld)\n",i
+*pnFirst
,(*pplFreqTable
)[i
]);
982 * \brief tunes to given frequency through IKsPropertySet call
984 * \param pTVTuner IAMTVTuner interface of capture device
985 * \param lFreq frequency to tune (in Hz)
987 * \return S_OK success
988 * \return apropriate error code otherwise
991 * Due to either bug in driver or error in following code calll to IKsProperty::Set
992 * in this methods always fail with error 0x8007007a.
994 * \todo test code on other machines and an error
996 static HRESULT
set_frequency_direct(IAMTVTuner
* pTVTuner
, long lFreq
)
999 DWORD dwSupported
= 0;
1001 KSPROPERTY_TUNER_MODE_CAPS_S mode_caps
;
1002 KSPROPERTY_TUNER_FREQUENCY_S frequency
;
1003 IKsPropertySet
*pKSProp
;
1005 mp_msg(MSGT_TV
, MSGL_DBG4
, "tvi_dshow: set_frequency_direct called\n");
1007 memset(&mode_caps
, 0, sizeof(mode_caps
));
1008 memset(&frequency
, 0, sizeof(frequency
));
1010 hr
= OLE_QUERYINTERFACE(pTVTuner
, IID_IKsPropertySet
, pKSProp
);
1012 return hr
; //no IKsPropertySet interface
1014 mode_caps
.Mode
= AMTUNER_MODE_TV
;
1015 hr
= OLE_CALL_ARGS(pKSProp
, QuerySupported
, &PROPSETID_TUNER
,
1016 KSPROPERTY_TUNER_MODE_CAPS
, &dwSupported
);
1018 OLE_RELEASE_SAFE(pKSProp
);
1022 if (!dwSupported
& KSPROPERTY_SUPPORT_GET
) {
1023 OLE_RELEASE_SAFE(pKSProp
);
1024 return E_FAIL
; //PROPSETID_TINER not supported
1027 hr
= OLE_CALL_ARGS(pKSProp
, Get
, &PROPSETID_TUNER
,
1028 KSPROPERTY_TUNER_MODE_CAPS
,
1029 INSTANCEDATA_OF_PROPERTY_PTR(&mode_caps
),
1030 INSTANCEDATA_OF_PROPERTY_SIZE(mode_caps
),
1031 &mode_caps
, sizeof(mode_caps
), &cbBytes
);
1033 frequency
.Frequency
= lFreq
;
1035 if (mode_caps
.Strategy
== KS_TUNER_STRATEGY_DRIVER_TUNES
)
1036 frequency
.TuningFlags
= KS_TUNER_TUNING_FINE
;
1038 frequency
.TuningFlags
= KS_TUNER_TUNING_EXACT
;
1040 if (lFreq
< mode_caps
.MinFrequency
|| lFreq
> mode_caps
.MaxFrequency
) {
1041 OLE_RELEASE_SAFE(pKSProp
);
1045 hr
= OLE_CALL_ARGS(pKSProp
, Set
, &PROPSETID_TUNER
,
1046 KSPROPERTY_TUNER_FREQUENCY
,
1047 INSTANCEDATA_OF_PROPERTY_PTR(&frequency
),
1048 INSTANCEDATA_OF_PROPERTY_SIZE(frequency
),
1049 &frequency
, sizeof(frequency
));
1051 OLE_RELEASE_SAFE(pKSProp
);
1055 OLE_RELEASE_SAFE(pKSProp
);
1061 * \brief find channel with nearest frequency and set it
1063 * \param priv driver's private data
1064 * \param lFreq frequency in Hz
1066 * \return S_OK if success
1067 * \return E_FAIL if error occured
1069 static HRESULT
set_nearest_freq(priv_t
* priv
, long lFreq
)
1075 TunerInputType tunerInput
;
1078 mp_msg(MSGT_TV
, MSGL_DBG4
, "tvi_dshow: set_nearest_freq called: %ld\n", lFreq
);
1079 if(priv
->freq_table_len
== -1 && !priv
->freq_table
) {
1081 hr
= OLE_CALL_ARGS(priv
->pTVTuner
, get_ConnectInput
, &lInput
);
1082 if(FAILED(hr
)){ //Falling back to 0
1086 hr
= OLE_CALL_ARGS(priv
->pTVTuner
, get_InputType
, lInput
, &tunerInput
);
1088 if (load_freq_table(chanlist2country(priv
->tv_param
->chanlist
), tunerInput
, &(priv
->freq_table
), &(priv
->freq_table_len
), &(priv
->first_channel
)) != S_OK
) {//FIXME
1089 priv
->freq_table_len
=0;
1090 priv
->freq_table
=NULL
;
1091 mp_tmsg(MSGT_TV
, MSGL_ERR
, "tvi_dshow: Unable to load frequency table from kstvtune.ax\n");
1094 mp_tmsg(MSGT_TV
, MSGL_V
, "tvi_dshow: loaded system (%s) frequency table for country id=%d (channels:%d).\n", tunerInput
== TunerInputAntenna
? "broadcast" : "cable",
1095 chanlist2country(priv
->tv_param
->chanlist
), priv
->freq_table_len
);
1098 if (priv
->freq_table_len
<= 0)
1101 //FIXME: rewrite search algo
1103 for (i
= 0; i
< priv
->freq_table_len
; i
++) {
1104 if (nChannel
== -1 || labs(lFreq
- priv
->freq_table
[i
]) < lFreqDiff
) {
1105 nChannel
= priv
->first_channel
+ i
;
1106 lFreqDiff
= labs(lFreq
- priv
->freq_table
[i
]);
1108 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
);
1110 if (nChannel
== -1) {
1111 mp_tmsg(MSGT_TV
,MSGL_ERR
, "tvi_dshow: Unable to find nearest channel in system frequency table\n");
1114 mp_msg(MSGT_TV
, MSGL_V
, "tvi_dshow: set_nearest_freq #%d (%ld)\n",nChannel
,priv
->freq_table
[nChannel
- priv
->first_channel
]);
1115 hr
= OLE_CALL_ARGS(priv
->pTVTuner
, put_Channel
, nChannel
,
1116 AMTUNER_SUBCHAN_DEFAULT
, AMTUNER_SUBCHAN_DEFAULT
);
1118 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
);
1125 * \brief setting frequency. decides whether use direct call/workaround
1127 * \param priv driver's private data
1128 * \param lFreq frequency in Hz
1130 * \return TVI_CONTROL_TRUE if success
1131 * \return TVI_CONTROL_FALSE if error occured
1133 * \todo check for freq boundary
1135 static int set_frequency(priv_t
* priv
, long lFreq
)
1139 mp_msg(MSGT_TV
, MSGL_DBG4
, "tvi_dshow: set_frequency called: %ld\n", lFreq
);
1140 if (!priv
->pTVTuner
)
1141 return TVI_CONTROL_FALSE
;
1142 if (priv
->direct_setfreq_call
) { //using direct call to set frequency
1143 hr
= set_frequency_direct(priv
->pTVTuner
, lFreq
);
1145 mp_tmsg(MSGT_TV
, MSGL_V
, "tvi_dshow: Unable to set frequency directly. OS built-in channels table will be used.\n");
1146 priv
->direct_setfreq_call
= 0;
1149 if (!priv
->direct_setfreq_call
) {
1150 hr
= set_nearest_freq(priv
, lFreq
);
1153 return TVI_CONTROL_FALSE
;
1155 priv
->pGrabber
->ClearBuffer(priv
->pGrabber
);
1157 return TVI_CONTROL_TRUE
;
1161 * \brief return current frequency from tuner (in Hz)
1163 * \param pTVTuner IAMTVTuner interface of tuner
1164 * \param plFreq address of variable that receives current frequency
1166 * \return S_OK success
1167 * \return E_POINTER pTVTuner==NULL || plFreq==NULL
1168 * \return apropriate error code otherwise
1170 static HRESULT
get_frequency_direct(IAMTVTuner
* pTVTuner
, long *plFreq
)
1173 KSPROPERTY_TUNER_STATUS_S TunerStatus
;
1175 IKsPropertySet
*pKSProp
;
1176 mp_msg(MSGT_TV
, MSGL_DBG4
, "tvi_dshow: get_frequency_direct called\n");
1181 hr
= OLE_QUERYINTERFACE(pTVTuner
, IID_IKsPropertySet
, pKSProp
);
1183 mp_msg(MSGT_TV
, MSGL_DBG2
, "tvi_dshow: Get freq QueryInterface failed\n");
1187 hr
= OLE_CALL_ARGS(pKSProp
, Get
, &PROPSETID_TUNER
,
1188 KSPROPERTY_TUNER_STATUS
,
1189 INSTANCEDATA_OF_PROPERTY_PTR(&TunerStatus
),
1190 INSTANCEDATA_OF_PROPERTY_SIZE(TunerStatus
),
1191 &TunerStatus
, sizeof(TunerStatus
), &cbBytes
);
1193 mp_msg(MSGT_TV
, MSGL_DBG2
, "tvi_dshow: Get freq Get failure\n");
1196 *plFreq
= TunerStatus
.CurrentFrequency
;
1201 * \brief gets current frequency
1203 * \param priv driver's private data structure
1204 * \param plFreq - pointer to long int to store frequency to (in Hz)
1206 * \return TVI_CONTROL_TRUE if success, TVI_CONTROL_FALSE otherwise
1208 static int get_frequency(priv_t
* priv
, long *plFreq
)
1212 mp_msg(MSGT_TV
, MSGL_DBG4
, "tvi_dshow: get_frequency called\n");
1214 if (!plFreq
|| !priv
->pTVTuner
)
1215 return TVI_CONTROL_FALSE
;
1217 if (priv
->direct_getfreq_call
) { //using direct call to get frequency
1218 hr
= get_frequency_direct(priv
->pTVTuner
, plFreq
);
1220 mp_tmsg(MSGT_TV
, MSGL_INFO
, "tvi_dshow: Unable to get frequency directly. OS built-in channels table will be used.\n");
1221 priv
->direct_getfreq_call
= 0;
1224 if (!priv
->direct_getfreq_call
) {
1225 hr
=OLE_CALL_ARGS(priv
->pTVTuner
, get_VideoFrequency
, plFreq
);
1227 return TVI_CONTROL_FALSE
;
1230 return TVI_CONTROL_TRUE
;
1234 * \brief get tuner capabilities
1236 * \param priv driver's private data
1238 static void get_capabilities(priv_t
* priv
)
1240 long lAvailableFormats
;
1243 long lInputPins
, lOutputPins
, lRelated
, lPhysicalType
;
1247 PIN_DIRECTION ThisPinDir
;
1249 IAMAudioInputMixer
*pIAMixer
;
1251 mp_msg(MSGT_TV
, MSGL_DBG4
, "tvi_dshow: get_capabilities called\n");
1252 if (priv
->pTVTuner
) {
1254 mp_tmsg(MSGT_TV
, MSGL_V
, "tvi_dshow: supported norms:");
1255 hr
= OLE_CALL_ARGS(priv
->pTVTuner
, get_AvailableTVFormats
,
1256 &lAvailableFormats
);
1258 tv_available_norms_count
= 0;
1260 for (i
= 0; i
< TV_NORMS_COUNT
; i
++) {
1261 if (lAvailableFormats
& tv_norms
[i
].index
) {
1262 tv_available_norms
[tv_available_norms_count
] = i
;
1263 mp_msg(MSGT_TV
, MSGL_V
, " %d=%s;",
1264 tv_available_norms_count
+ 1, tv_norms
[i
].name
);
1265 tv_available_norms_count
++;
1269 mp_msg(MSGT_TV
, MSGL_INFO
, "\n");
1271 if (priv
->pCrossbar
) {
1272 OLE_CALL_ARGS(priv
->pCrossbar
, get_PinCounts
, &lOutputPins
,
1275 tv_available_inputs
= malloc(sizeof(long) * lInputPins
);
1276 tv_available_inputs_count
= 0;
1278 mp_tmsg(MSGT_TV
, MSGL_V
, "tvi_dshow: available video inputs:");
1279 for (i
= 0; i
< lInputPins
; i
++) {
1280 OLE_CALL_ARGS(priv
->pCrossbar
, get_CrossbarPinInfo
, 1, i
,
1281 &lRelated
, &lPhysicalType
);
1283 if (lPhysicalType
< 0x1000) {
1284 tv_available_inputs
[tv_available_inputs_count
++] = i
;
1285 mp_msg(MSGT_TV
, MSGL_V
, " %d=%s;",
1286 tv_available_inputs_count
- 1,
1287 physcon2str(lPhysicalType
));
1290 mp_msg(MSGT_TV
, MSGL_INFO
, "\n");
1292 set_crossbar_input(priv
, 0);
1295 if (priv
->adev_index
!= -1) {
1296 hr
= OLE_CALL_ARGS(priv
->chains
[1]->pCaptureFilter
, EnumPins
, &pEnum
);
1299 mp_tmsg(MSGT_TV
, MSGL_V
, "tvi_dshow: available audio inputs:");
1301 while (OLE_CALL_ARGS(pEnum
, Next
, 1, &pPin
, NULL
) == S_OK
) {
1302 memset(&pi
, 0, sizeof(pi
));
1303 memset(tmp
, 0, 200);
1304 OLE_CALL_ARGS(pPin
, QueryDirection
, &ThisPinDir
);
1305 if (ThisPinDir
== PINDIR_INPUT
) {
1306 OLE_CALL_ARGS(pPin
, QueryPinInfo
, &pi
);
1307 wtoa(pi
.achName
, tmp
, 200);
1308 OLE_RELEASE_SAFE(pi
.pFilter
);
1309 mp_msg(MSGT_TV
, MSGL_V
, " %d=%s", i
, tmp
);
1310 mp_msg(MSGT_TV
, MSGL_DBG3
, " (%p)", pPin
);
1311 hr
= OLE_QUERYINTERFACE(pPin
, IID_IAMAudioInputMixer
,pIAMixer
);
1312 if (SUCCEEDED(hr
)) {
1313 if (i
== priv
->tv_param
->audio_id
) {
1314 OLE_CALL_ARGS(pIAMixer
, put_Enable
, TRUE
);
1315 if(priv
->tv_param
->volume
>0)
1316 OLE_CALL_ARGS(pIAMixer
, put_MixLevel
, 0.01 * priv
->tv_param
->volume
);
1319 OLE_CALL_ARGS(pIAMixer
, put_MixLevel
, 1.0);
1321 mp_tmsg(MSGT_TV
, MSGL_V
, "(selected)");
1323 OLE_CALL_ARGS(pIAMixer
, put_Enable
, FALSE
);
1325 OLE_CALL_ARGS(pIAMixer
, put_MixLevel
, 0.0);
1328 OLE_RELEASE_SAFE(pIAMixer
);
1330 mp_msg(MSGT_TV
, MSGL_V
, ";");
1331 OLE_RELEASE_SAFE(pPin
);
1335 mp_msg(MSGT_TV
, MSGL_INFO
, "\n");
1336 OLE_RELEASE_SAFE(pEnum
);
1341 *---------------------------------------------------------------------------------------
1343 * Filter related methods
1345 *---------------------------------------------------------------------------------------
1348 * \brief building in graph audio/video capture chain
1350 * \param priv driver's private data
1351 * \param pCaptureFilter pointer to capture device's IBaseFilter interface
1352 * \param pbuf ringbuffer data structure
1353 * \param pmt media type for chain (AM_MEDIA_TYPE)
1355 * \note routine does not frees memory, allocated for grabber_rinbuffer_s structure
1357 static HRESULT
build_sub_graph(priv_t
* priv
, chain_t
* chain
, const GUID
* ppin_category
)
1360 int nFormatProbed
= 0;
1365 IBaseFilter
*pNR
= NULL
;
1369 //No supported formats
1370 if(!chain
->arpmt
[0])
1374 hr
= OLE_CALL_ARGS(priv
->pBuilder
, FindPin
,
1375 (IUnknown
*) chain
->pCaptureFilter
,
1376 PINDIR_OUTPUT
, ppin_category
,
1377 chain
->majortype
, FALSE
, 0, &chain
->pCapturePin
);
1379 mp_msg(MSGT_TV
,MSGL_DBG2
, "tvi_dshow: FindPin(pCapturePin) call failed. Error:0x%x\n", (unsigned int)hr
);
1382 /* Addinf SampleGrabber filter for video stream */
1383 hr
= CoCreateInstance((GUID
*) & CLSID_SampleGrabber
, NULL
,CLSCTX_INPROC_SERVER
, &IID_IBaseFilter
,(void *) &chain
->pSGF
);
1385 mp_msg(MSGT_TV
,MSGL_DBG2
, "tvi_dshow: CoCreateInstance(SampleGrabber) call failed. Error:0x%x\n", (unsigned int)hr
);
1388 hr
= OLE_CALL_ARGS(priv
->pGraph
, AddFilter
, chain
->pSGF
, L
"Sample Grabber");
1390 mp_msg(MSGT_TV
,MSGL_DBG2
,"tvi_dshow: AddFilter(SampleGrabber) call failed. Error:0x%x\n", (unsigned int)hr
);
1393 hr
= OLE_CALL_ARGS(priv
->pBuilder
, FindPin
, (IUnknown
*) chain
->pSGF
,PINDIR_INPUT
, NULL
, NULL
, FALSE
, 0, &chain
->pSGIn
);
1395 mp_msg(MSGT_TV
,MSGL_DBG2
,"tvi_dshow: FindPin(pSGIn) call failed. Error:0x%x\n", (unsigned int)hr
);
1398 hr
= OLE_CALL_ARGS(priv
->pBuilder
, FindPin
, (IUnknown
*) chain
->pSGF
,PINDIR_OUTPUT
, NULL
, NULL
, FALSE
, 0, &pSGOut
);
1400 mp_msg(MSGT_TV
,MSGL_DBG2
,"tvi_dshow: FindPin(pSGOut) call failed. Error:0x%x\n", (unsigned int)hr
);
1404 /* creating ringbuffer for video samples */
1405 chain
->pCSGCB
= CSampleGrabberCB_Create(chain
->rbuf
);
1407 mp_msg(MSGT_TV
,MSGL_DBG2
, "tvi_dshow: CSampleGrabberCB_Create(pbuf) call failed. Error:0x%x\n", (unsigned int)E_OUTOFMEMORY
);
1411 /* initializing SampleGrabber filter */
1412 hr
= OLE_QUERYINTERFACE(chain
->pSGF
, IID_ISampleGrabber
, chain
->pSG
);
1414 mp_msg(MSGT_TV
,MSGL_DBG2
,"tvi_dshow: QueryInterface(IID_ISampleGrabber) call failed. Error:0x%x\n", (unsigned int)hr
);
1417 // hr = OLE_CALL_ARGS(pSG, SetCallback, (ISampleGrabberCB *) pCSGCB, 1); //we want to receive copy of sample's data
1418 hr
= OLE_CALL_ARGS(chain
->pSG
, SetCallback
, (ISampleGrabberCB
*) chain
->pCSGCB
, 0); //we want to receive sample
1421 mp_msg(MSGT_TV
,MSGL_DBG2
,"tvi_dshow: SetCallback(pSG) call failed. Error:0x%x\n", (unsigned int)hr
);
1424 hr
= OLE_CALL_ARGS(chain
->pSG
, SetOneShot
, FALSE
); //... for all frames
1426 mp_msg(MSGT_TV
,MSGL_DBG2
,"tvi_dshow: SetOneShot(pSG) call failed. Error:0x%x\n", (unsigned int)hr
);
1429 hr
= OLE_CALL_ARGS(chain
->pSG
, SetBufferSamples
, FALSE
); //... do not buffer samples in sample grabber
1431 mp_msg(MSGT_TV
,MSGL_DBG2
,"tvi_dshow: SetBufferSamples(pSG) call failed. Error:0x%x\n", (unsigned int)hr
);
1435 if(priv
->tv_param
->normalize_audio_chunks
&& chain
->type
==audio
){
1436 set_buffer_preference(20,(WAVEFORMATEX
*)(chain
->arpmt
[nFormatProbed
]->pbFormat
),chain
->pCapturePin
,chain
->pSGIn
);
1439 for(nFormatProbed
=0; chain
->arpmt
[nFormatProbed
]; nFormatProbed
++)
1441 DisplayMediaType("Probing format", chain
->arpmt
[nFormatProbed
]);
1442 hr
= OLE_CALL_ARGS(chain
->pSG
, SetMediaType
, chain
->arpmt
[nFormatProbed
]); //set desired mediatype
1444 mp_msg(MSGT_TV
,MSGL_DBG2
,"tvi_dshow: SetMediaType(pSG) call failed. Error:0x%x\n", (unsigned int)hr
);
1447 /* connecting filters together: VideoCapture --> SampleGrabber */
1448 hr
= OLE_CALL_ARGS(priv
->pGraph
, Connect
, chain
->pCapturePin
, chain
->pSGIn
);
1450 mp_msg(MSGT_TV
,MSGL_DBG2
,"tvi_dshow: Unable to create pCapturePin<->pSGIn connection. Error:0x%x\n", (unsigned int)hr
);
1456 if(!chain
->arpmt
[nFormatProbed
])
1458 mp_msg(MSGT_TV
, MSGL_WARN
, "tvi_dshow: Unable to negotiate media format\n");
1463 hr
= OLE_CALL_ARGS(chain
->pCapturePin
, ConnectionMediaType
, chain
->pmt
);
1466 mp_tmsg(MSGT_TV
, MSGL_WARN
, "tvi_dshow: Unable to get actual mediatype (Error:0x%x). Assuming equal to requested.\n", (unsigned int)hr
);
1469 if(priv
->tv_param
->hidden_video_renderer
){
1470 IEnumFilters
* pEnum
;
1471 IBaseFilter
* pFilter
;
1473 hr
=OLE_CALL_ARGS(priv
->pBuilder
,RenderStream
,NULL
,NULL
,(IUnknown
*)chain
->pCapturePin
,NULL
,NULL
);
1475 OLE_CALL_ARGS(priv
->pGraph
, EnumFilters
, &pEnum
);
1476 while (OLE_CALL_ARGS(pEnum
, Next
, 1, &pFilter
, NULL
) == S_OK
) {
1477 LPVIDEOWINDOW pVideoWindow
;
1478 hr
= OLE_QUERYINTERFACE(pFilter
, IID_IVideoWindow
, pVideoWindow
);
1481 OLE_CALL_ARGS(pVideoWindow
,put_Visible
,/* OAFALSE*/ 0);
1482 OLE_CALL_ARGS(pVideoWindow
,put_AutoShow
,/* OAFALSE*/ 0);
1483 OLE_RELEASE_SAFE(pVideoWindow
);
1485 OLE_RELEASE_SAFE(pFilter
);
1487 OLE_RELEASE_SAFE(pEnum
);
1492 Code below is disabled, because terminating chain with NullRenderer leads to jerky video.
1493 Perhaps, this happens because NullRenderer filter discards each received
1494 frame while discarded frames causes live source filter to dramatically reduce frame rate.
1496 /* adding sink for video stream */
1497 hr
= CoCreateInstance((GUID
*) & CLSID_NullRenderer
, NULL
,CLSCTX_INPROC_SERVER
, &IID_IBaseFilter
,(void *) &pNR
);
1499 mp_msg(MSGT_TV
,MSGL_DBG2
,"tvi_dshow: CoCreateInstance(NullRenderer) call failed. Error:0x%x\n", (unsigned int)hr
);
1502 hr
= OLE_CALL_ARGS(priv
->pGraph
, AddFilter
, pNR
, L
"Null Renderer");
1504 mp_msg(MSGT_TV
,MSGL_DBG2
,"tvi_dshow: AddFilter(NullRenderer) call failed. Error:0x%x\n", (unsigned int)hr
);
1507 hr
= OLE_CALL_ARGS(priv
->pBuilder
, FindPin
, (IUnknown
*) pNR
,PINDIR_INPUT
, NULL
, NULL
, FALSE
, 0, &pNRIn
);
1509 mp_msg(MSGT_TV
,MSGL_DBG2
,"tvi_dshow: FindPin(pNRIn) call failed. Error:0x%x\n", (unsigned int)hr
);
1513 Prevent ending VBI chain with NullRenderer filter, because this causes VBI pin disconnection
1515 if(memcmp(&(arpmt
[nFormatProbed
]->majortype
),&MEDIATYPE_VBI
,16)){
1516 /* connecting filters together: SampleGrabber --> NullRenderer */
1517 hr
= OLE_CALL_ARGS(priv
->pGraph
, Connect
, pSGOut
, pNRIn
);
1519 mp_msg(MSGT_TV
,MSGL_DBG2
,"tvi_dshow: Unable to create pSGOut<->pNRIn connection. Error:0x%x\n", (unsigned int)hr
);
1529 OLE_RELEASE_SAFE(pSGOut
);
1530 OLE_RELEASE_SAFE(pNR
);
1531 OLE_RELEASE_SAFE(pNRIn
);
1537 * \brief configures crossbar for grabbing video stream from given input
1539 * \param priv driver's private data
1540 * \param input index of available video input to get data from
1542 * \return TVI_CONTROL_TRUE success
1543 * \return TVI_CONTROL_FALSE error
1545 static int set_crossbar_input(priv_t
* priv
, int input
)
1548 int i
, nVideoDecoder
, nAudioDecoder
;
1549 long lInput
, lInputRelated
, lRelated
, lPhysicalType
, lOutputPins
,
1552 mp_msg(MSGT_TV
, MSGL_DBG4
, "tvi_dshow: Configuring crossbar\n");
1553 if (!priv
->pCrossbar
|| input
< 0
1554 || input
>= tv_available_inputs_count
)
1555 return TVI_CONTROL_FALSE
;
1557 OLE_CALL_ARGS(priv
->pCrossbar
, get_PinCounts
, &lOutputPins
, &lInputPins
);
1559 lInput
= tv_available_inputs
[input
];
1561 if (lInput
< 0 || lInput
>= lInputPins
)
1562 return TVI_CONTROL_FALSE
;
1564 OLE_CALL_ARGS(priv
->pCrossbar
, get_CrossbarPinInfo
, 1 /* input */ , lInput
,
1565 &lInputRelated
, &lPhysicalType
);
1567 nVideoDecoder
= nAudioDecoder
= -1;
1568 for (i
= 0; i
< lOutputPins
; i
++) {
1569 OLE_CALL_ARGS(priv
->pCrossbar
, get_CrossbarPinInfo
, 0 /*output */ , i
,
1570 &lRelated
, &lPhysicalType
);
1571 if (lPhysicalType
== PhysConn_Video_VideoDecoder
)
1573 if (lPhysicalType
== PhysConn_Audio_AudioDecoder
)
1576 if (nVideoDecoder
>= 0) {
1577 //connecting given input with video decoder
1578 hr
= OLE_CALL_ARGS(priv
->pCrossbar
, Route
, nVideoDecoder
, lInput
);
1580 mp_tmsg(MSGT_TV
,MSGL_ERR
,"Unable to connect given input to video decoder. Error:0x%x\n", (unsigned int)hr
);
1581 return TVI_CONTROL_FALSE
;
1584 if (nAudioDecoder
>= 0 && lInputRelated
>= 0) {
1585 hr
= OLE_CALL_ARGS(priv
->pCrossbar
, Route
, nAudioDecoder
,
1588 mp_tmsg(MSGT_TV
,MSGL_ERR
,"Unable to connect given input to audio decoder. Error:0x%x\n", (unsigned int)hr
);
1589 return TVI_CONTROL_FALSE
;
1592 return TVI_CONTROL_TRUE
;
1596 * \brief adjusts video control (hue,saturation,contrast,brightess)
1598 * \param priv driver's private data
1599 * \param control which control to adjust
1600 * \param value new value for control (0-100)
1602 * \return TVI_CONTROL_TRUE success
1603 * \return TVI_CONTROL_FALSE error
1605 static int set_control(priv_t
* priv
, int control
, int value
)
1607 long lMin
, lMax
, lStepping
, lDefault
, lFlags
, lValue
;
1610 mp_msg(MSGT_TV
, MSGL_DBG4
, "tvi_dshow: set_control called\n");
1611 if (value
< -100 || value
> 100 || !priv
->pVideoProcAmp
)
1612 return TVI_CONTROL_FALSE
;
1614 hr
= OLE_CALL_ARGS(priv
->pVideoProcAmp
, GetRange
, control
,
1615 &lMin
, &lMax
, &lStepping
, &lDefault
, &lFlags
);
1616 if (FAILED(hr
) || lFlags
!= VideoProcAmp_Flags_Manual
)
1617 return TVI_CONTROL_FALSE
;
1619 lValue
= lMin
+ (value
+ 100) * (lMax
- lMin
) / 200;
1621 Workaround for ATI AIW 7500. The driver reports: max=255, stepping=256
1623 if (lStepping
> lMax
) {
1624 mp_msg(MSGT_TV
, MSGL_DBG3
,
1625 "tvi_dshow: Stepping (%ld) is bigger than max value (%ld) for control %d. Assuming 1\n",
1626 lStepping
, lMax
,control
);
1629 lValue
-= lValue
% lStepping
;
1630 hr
= OLE_CALL_ARGS(priv
->pVideoProcAmp
, Set
, control
, lValue
,
1631 VideoProcAmp_Flags_Manual
);
1633 return TVI_CONTROL_FALSE
;
1635 return TVI_CONTROL_TRUE
;
1639 * \brief get current value of video control (hue,saturation,contrast,brightess)
1641 * \param priv driver's private data
1642 * \param control which control to adjust
1643 * \param pvalue address of variable thar receives current value
1645 * \return TVI_CONTROL_TRUE success
1646 * \return TVI_CONTROL_FALSE error
1648 static int get_control(priv_t
* priv
, int control
, int *pvalue
)
1650 long lMin
, lMax
, lStepping
, lDefault
, lFlags
, lValue
;
1653 mp_msg(MSGT_TV
, MSGL_DBG4
, "tvi_dshow: get_control called\n");
1654 if (!pvalue
|| !priv
->pVideoProcAmp
)
1655 return TVI_CONTROL_FALSE
;
1657 hr
= OLE_CALL_ARGS(priv
->pVideoProcAmp
, GetRange
, control
,
1658 &lMin
, &lMax
, &lStepping
, &lDefault
, &lFlags
);
1660 return TVI_CONTROL_FALSE
;
1663 return TVI_CONTROL_TRUE
;
1666 hr
= OLE_CALL_ARGS(priv
->pVideoProcAmp
, Get
, control
, &lValue
, &lFlags
);
1668 return TVI_CONTROL_FALSE
;
1670 *pvalue
= 200 * (lValue
- lMin
) / (lMax
- lMin
) - 100;
1672 return TVI_CONTROL_TRUE
;
1676 * \brief create AM_MEDIA_TYPE structure, corresponding to given FourCC code and width/height/fps
1677 * \param fcc FourCC code for video format
1678 * \param width picture width
1679 * \param height pciture height
1680 * \param fps frames per second (required for bitrate calculation)
1682 * \return pointer to AM_MEDIA_TYPE structure if success, NULL - otherwise
1684 static AM_MEDIA_TYPE
* create_video_format(int fcc
, int width
, int height
, int fps
)
1688 VIDEOINFOHEADER vHdr
;
1690 /* Check given fcc in lookup table*/
1691 for(i
=0; img_fmt_list
[i
].fmt
&& img_fmt_list
[i
].fmt
!=fcc
; i
++) /* NOTHING */;
1692 if(!img_fmt_list
[i
].fmt
)
1695 memset(&mt
, 0, sizeof(AM_MEDIA_TYPE
));
1696 memset(&vHdr
, 0, sizeof(VIDEOINFOHEADER
));
1698 vHdr
.bmiHeader
.biSize
= sizeof(vHdr
.bmiHeader
);
1699 vHdr
.bmiHeader
.biWidth
= width
;
1700 vHdr
.bmiHeader
.biHeight
= height
;
1701 //FIXME: is biPlanes required too?
1702 //vHdr.bmiHeader.biPlanes = img_fmt_list[i].nPlanes;
1703 vHdr
.bmiHeader
.biBitCount
= img_fmt_list
[i
].nBits
;
1704 vHdr
.bmiHeader
.biCompression
= img_fmt_list
[i
].nCompression
;
1705 vHdr
.bmiHeader
.biSizeImage
= width
* height
* img_fmt_list
[i
].nBits
/ 8;
1706 vHdr
.dwBitRate
= vHdr
.bmiHeader
.biSizeImage
* 8 * fps
;
1708 mt
.pbFormat
= (char*)&vHdr
;
1709 mt
.cbFormat
= sizeof(vHdr
);
1711 mt
.majortype
= MEDIATYPE_Video
;
1712 mt
.subtype
= *img_fmt_list
[i
].subtype
;
1713 mt
.formattype
= FORMAT_VideoInfo
;
1715 mt
.bFixedSizeSamples
= 1;
1716 mt
.bTemporalCompression
= 0;
1717 mt
.lSampleSize
= vHdr
.bmiHeader
.biSizeImage
;
1719 return CreateMediaType(&mt
);
1723 * \brief extracts fcc,width,height from AM_MEDIA_TYPE
1725 * \param pmt pointer to AM_MEDIA_TYPE to extract data from
1726 * \param pfcc address of variable that receives FourCC
1727 * \param pwidth address of variable that receives width
1728 * \param pheight address of variable that recevies height
1730 * \return 1 if data extracted successfully, 0 - otherwise
1732 static int extract_video_format(AM_MEDIA_TYPE
* pmt
, int *pfcc
,
1733 int *pwidth
, int *pheight
)
1735 mp_msg(MSGT_TV
, MSGL_DBG4
, "tvi_dshow: extract_video_format called\n");
1740 if (memcmp(&(pmt
->formattype
), &FORMAT_VideoInfo
, 16) != 0)
1743 *pfcc
= subtype2imgfmt(&(pmt
->subtype
));
1745 *pwidth
= ((VIDEOINFOHEADER
*) pmt
->pbFormat
)->bmiHeader
.biWidth
;
1747 *pheight
= ((VIDEOINFOHEADER
*) pmt
->pbFormat
)->bmiHeader
.biHeight
;
1752 * \brief extracts samplerate,bits,channels from AM_MEDIA_TYPE
1754 * \param pmt pointer to AM_MEDIA_TYPE to extract data from
1755 * \param pfcc address of variable that receives samplerate
1756 * \param pwidth address of variable that receives number of bits per sample
1757 * \param pheight address of variable that recevies number of channels
1759 * \return 1 if data extracted successfully, 0 - otherwise
1761 static int extract_audio_format(AM_MEDIA_TYPE
* pmt
, int *psamplerate
,
1762 int *pbits
, int *pchannels
)
1764 mp_msg(MSGT_TV
, MSGL_DBG4
, "tvi_dshow: extract_audio_format called\n");
1769 if (memcmp(&(pmt
->formattype
), &FORMAT_WaveFormatEx
, 16) != 0)
1772 *psamplerate
= ((WAVEFORMATEX
*) pmt
->pbFormat
)->nSamplesPerSec
;
1774 *pbits
= ((WAVEFORMATEX
*) pmt
->pbFormat
)->wBitsPerSample
;
1776 *pchannels
= ((WAVEFORMATEX
*) pmt
->pbFormat
)->nChannels
;
1781 * \brief checks if AM_MEDIA_TYPE compatible with given samplerate,bits,channels
1783 * \param pmt pointer to AM_MEDIA_TYPE for check
1784 * \param samplerate audio samplerate
1785 * \param bits bits per sample
1786 * \param channels number of audio channels
1788 * \return 1 if AM_MEDIA_TYPE compatible
1791 static int check_audio_format(AM_MEDIA_TYPE
* pmt
, int samplerate
,
1792 int bits
, int channels
)
1794 mp_msg(MSGT_TV
, MSGL_DBG4
, "tvi_dshow: check_audio_format called\n");
1797 if (memcmp(&(pmt
->majortype
), &MEDIATYPE_Audio
, 16) != 0)
1799 if (memcmp(&(pmt
->subtype
), &MEDIASUBTYPE_PCM
, 16) != 0)
1801 if (memcmp(&(pmt
->formattype
), &FORMAT_WaveFormatEx
, 16) != 0)
1805 if (((WAVEFORMATEX
*) pmt
->pbFormat
)->nSamplesPerSec
!= samplerate
)
1807 if (((WAVEFORMATEX
*) pmt
->pbFormat
)->wBitsPerSample
!= bits
)
1810 && ((WAVEFORMATEX
*) pmt
->pbFormat
)->nChannels
!= channels
)
1817 * \brief checks if AM_MEDIA_TYPE compatible with given fcc,width,height
1819 * \param pmt pointer to AM_MEDIA_TYPE for check
1820 * \param fcc FourCC (compression)
1821 * \param width width of picture
1822 * \param height height of picture
1824 * \return 1 if AM_MEDIA_TYPE compatible
1828 * width and height are currently not used
1831 * add width/height check
1833 static int check_video_format(AM_MEDIA_TYPE
* pmt
, int fcc
, int width
,
1836 mp_msg(MSGT_TV
, MSGL_DBG4
, "tvi_dshow: check_video_format called\n");
1839 if (memcmp(&(pmt
->majortype
), &MEDIATYPE_Video
, 16) != 0)
1841 if (subtype2imgfmt(&(pmt
->subtype
)) != fcc
)
1847 * \brief converts DirectShow subtype to MPlayer's IMGFMT
1849 * \param subtype DirectShow subtype for video format
1851 * \return MPlayer's IMGFMT or 0 if error occured
1853 static int subtype2imgfmt(const GUID
* subtype
)
1856 for (i
= 0; img_fmt_list
[i
].fmt
; i
++) {
1857 if (memcmp(subtype
, img_fmt_list
[i
].subtype
, 16) == 0)
1858 return img_fmt_list
[i
].fmt
;
1864 * \brief prints filter name and it pins
1866 * \param pFilter - IBaseFilter to get data from
1868 * \return S_OK if success, error code otherwise
1870 static HRESULT
show_filter_info(IBaseFilter
* pFilter
)
1874 LPENUMPINS pEnum
= 0;
1876 PIN_DIRECTION ThisPinDir
;
1881 mp_msg(MSGT_TV
, MSGL_DBG4
, "tvi_dshow: show_filter_info called\n");
1882 memset(&fi
, 0, sizeof(fi
));
1883 memset(tmp
, 0, 200);
1885 OLE_CALL_ARGS(pFilter
, QueryFilterInfo
, &fi
);
1886 OLE_RELEASE_SAFE(fi
.pGraph
);
1887 wtoa(fi
.achName
, tmp
, 200);
1888 mp_msg(MSGT_TV
, MSGL_DBG2
, "tvi_dshow: BaseFilter (%p): Name=%s, Graph=%p output pins:",
1889 pFilter
, tmp
, fi
.pGraph
);
1890 hr
= OLE_CALL_ARGS(pFilter
, EnumPins
, &pEnum
);
1894 while (OLE_CALL_ARGS(pEnum
, Next
, 1, &pPin
, NULL
) == S_OK
) {
1895 memset(&pi
, 0, sizeof(pi
));
1896 memset(tmp
, 0, 200);
1897 OLE_CALL_ARGS(pPin
, QueryDirection
, &ThisPinDir
);
1898 if (ThisPinDir
== PINDIR_OUTPUT
) {
1899 OLE_CALL_ARGS(pPin
, QueryPinInfo
, &pi
);
1900 wtoa(pi
.achName
, tmp
, 200);
1901 OLE_RELEASE_SAFE(pi
.pFilter
);
1902 mp_msg(MSGT_TV
, MSGL_DBG2
, " %d=%s", i
, tmp
);
1903 mp_msg(MSGT_TV
, MSGL_DBG3
, " (%p)", pPin
);
1904 mp_msg(MSGT_TV
, MSGL_DBG2
, ";");
1905 OLE_RELEASE_SAFE(pPin
);
1909 mp_msg(MSGT_TV
, MSGL_DBG2
, "\n");
1910 OLE_RELEASE_SAFE(pEnum
);
1915 * \brief gets device's frendly in ANSI encoding
1917 * \param pM IMoniker interface, got in enumeration process
1918 * \param category device category
1920 * \return TVI_CONTROL_TRUE if operation succeded, TVI_CONTROL_FALSE - otherwise
1922 static int get_device_name(IMoniker
* pM
, char *pBuf
, int nLen
)
1926 IPropertyBag
*pPropBag
;
1927 hr
= OLE_CALL_ARGS(pM
, BindToStorage
, 0, 0, &IID_IPropertyBag
,(void *) &pPropBag
);
1929 mp_msg(MSGT_TV
, MSGL_DBG2
, "tvi_dshow: Call to BindToStorage failed\n");
1930 return TVI_CONTROL_FALSE
;
1933 hr
= OLE_CALL_ARGS(pPropBag
, Read
, L
"Description", (LPVARIANT
) & var
,
1936 hr
= OLE_CALL_ARGS(pPropBag
, Read
, L
"FriendlyName", (LPVARIANT
) & var
,
1939 OLE_RELEASE_SAFE(pPropBag
);
1940 if (SUCCEEDED(hr
)) {
1941 wtoa(var
.bstrVal
, pBuf
, nLen
);
1942 return TVI_CONTROL_TRUE
;
1944 return TVI_CONTROL_FALSE
;
1948 * \brief find capture device at given index
1950 * \param index device index to search for (-1 mean only print available)
1951 * \param category device category
1953 * \return IBaseFilter interface for capture device with given index
1955 * Sample values for category:
1956 * CLSID_VideoInputDeviceCategory - Video Capture Sources
1957 * CLSID_AudioInputDeviceCategory - Audio Capture Sources
1958 * See DirectShow SDK documentation for other possible values
1960 static IBaseFilter
*find_capture_device(int index
, REFCLSID category
)
1962 IBaseFilter
*pFilter
= NULL
;
1963 ICreateDevEnum
*pDevEnum
= NULL
;
1964 IEnumMoniker
*pClassEnum
= NULL
;
1969 char tmp
[DEVICE_NAME_MAX_LEN
+ 1];
1970 hr
= CoCreateInstance((GUID
*) & CLSID_SystemDeviceEnum
, NULL
,
1971 CLSCTX_INPROC_SERVER
, &IID_ICreateDevEnum
,
1972 (void *) &pDevEnum
);
1974 mp_msg(MSGT_TV
, MSGL_DBG2
, "tvi_dshow: Unable to create device enumerator\n");
1978 hr
= OLE_CALL_ARGS(pDevEnum
, CreateClassEnumerator
, category
, &pClassEnum
, 0);
1979 OLE_RELEASE_SAFE(pDevEnum
);
1981 mp_msg(MSGT_TV
, MSGL_DBG2
, "tvi_dshow: Unable to create class enumerator\n");
1984 if (hr
== S_FALSE
) {
1985 mp_msg(MSGT_TV
, MSGL_DBG2
, "tvi_dshow: No capture devices found\n");
1989 OLE_CALL(pClassEnum
,Reset
);
1990 for (i
= 0; OLE_CALL_ARGS(pClassEnum
, Next
, 1, &pM
, &cFetched
) == S_OK
; i
++) {
1991 if(get_device_name(pM
, tmp
, DEVICE_NAME_MAX_LEN
)!=TVI_CONTROL_TRUE
)
1992 mp_tmsg(MSGT_TV
, MSGL_ERR
, "tvi_dshow: Unable to get name for device #%d\n", i
);
1994 mp_tmsg(MSGT_TV
, MSGL_V
, "tvi_dshow: Device #%d: %s\n", i
, tmp
);
1995 if (index
!= -1 && i
== index
) {
1996 mp_tmsg(MSGT_TV
, MSGL_INFO
, "tvi_dshow: Using device #%d: %s\n", index
, tmp
);
1997 hr
= OLE_CALL_ARGS(pM
, BindToObject
, 0, 0, &IID_IBaseFilter
,(void *) &pFilter
);
2001 OLE_RELEASE_SAFE(pM
);
2003 if (index
!= -1 && !pFilter
) {
2004 mp_tmsg(MSGT_TV
, MSGL_ERR
, "tvi_dshow: Device #%d not found\n",
2007 OLE_RELEASE_SAFE(pClassEnum
);
2013 * \brief get array of available formats through call to IAMStreamConfig::GetStreamCaps
2015 * \praram[in] chain chain data structure
2017 * \return S_OK success
2018 * \return E_POINTER one of parameters is NULL
2019 * \return E_FAIL required size of buffer is unknown for given media type
2020 * \return E_OUTOFMEMORY not enough memory
2021 * \return other error code from called methods
2024 * last items of chain->arpmt and chain->arStreamCaps will be NULL
2026 static HRESULT
get_available_formats_stream(chain_t
*chain
)
2028 AM_MEDIA_TYPE
**arpmt
;
2035 mp_msg(MSGT_TV
, MSGL_DBG4
,
2036 "tvi_dshow: get_available_formats_stream called\n");
2038 if (!chain
->pStreamConfig
)
2041 hr
=OLE_CALL_ARGS(chain
->pStreamConfig
, GetNumberOfCapabilities
, &count
, &size
);
2043 mp_msg(MSGT_TV
, MSGL_DBG4
,
2044 "tvi_dshow: Call to GetNumberOfCapabilities failed (get_available_formats_stream)\n");
2047 if (chain
->type
== video
){
2048 if (size
!= sizeof(VIDEO_STREAM_CONFIG_CAPS
)) {
2049 mp_msg(MSGT_TV
, MSGL_DBG4
,
2050 "tvi_dshow: Wrong video structure size for GetNumberOfCapabilities (get_available_formats_stream)\n");
2053 } else if (chain
->type
== audio
){
2054 if (size
!= sizeof(AUDIO_STREAM_CONFIG_CAPS
)) {
2055 mp_msg(MSGT_TV
, MSGL_DBG4
,
2056 "tvi_dshow: Wrong audio structure size for GetNumberOfCapabilities (get_available_formats_stream)\n");
2060 mp_tmsg(MSGT_TV
, MSGL_ERR
, "tvi_dshow: Unsupported media type passed to %s\n","get_available_formats_stream");
2065 arpmt
= malloc((count
+ 1) * sizeof(AM_MEDIA_TYPE
*));
2067 memset(arpmt
, 0, (count
+ 1) * sizeof(AM_MEDIA_TYPE
*));
2069 pBuf
= malloc((count
+ 1) * sizeof(void *));
2071 memset(pBuf
, 0, (count
+ 1) * sizeof(void *));
2073 for (i
= 0; i
< count
; i
++) {
2074 pBuf
[i
] = malloc(size
);
2079 hr
= OLE_CALL_ARGS(chain
->pStreamConfig
, GetStreamCaps
, i
,
2080 &(arpmt
[i
]), pBuf
[i
]);
2085 chain
->arpmt
= arpmt
;
2086 chain
->arStreamCaps
= pBuf
;
2092 for (i
= 0; i
< count
; i
++) {
2095 if (arpmt
&& arpmt
[i
])
2096 DeleteMediaType(arpmt
[i
]);
2101 mp_msg(MSGT_TV
, MSGL_DBG4
, "tvi_dshow: Call to GetStreamCaps failed (get_available_formats_stream)\n");
2104 return E_OUTOFMEMORY
;
2110 * \brief returns allocates an array and store available media formats for given pin type to it
2112 * \param pBuilder ICaptureGraphBuilder2 interface of graph builder
2113 * \param chain chain data structure
2115 * \return S_OK success
2116 * \return E_POINTER one of given pointers is null
2117 * \return apropriate error code otherwise
2119 static HRESULT
get_available_formats_pin(ICaptureGraphBuilder2
* pBuilder
,
2122 IEnumMediaTypes
*pEnum
;
2128 AM_MEDIA_TYPE
**arpmt
; //This will be real array
2129 VIDEO_STREAM_CONFIG_CAPS
*pVideoCaps
;
2130 AUDIO_STREAM_CONFIG_CAPS
*pAudioCaps
;
2133 mp_msg(MSGT_TV
, MSGL_DBG4
,
2134 "tvi_dshow: get_available_formats_pin called\n");
2135 if (!pBuilder
|| !chain
->pCaptureFilter
)
2138 if (!chain
->pCapturePin
)
2140 hr
= OLE_CALL_ARGS(pBuilder
, FindPin
,
2141 (IUnknown
*) chain
->pCaptureFilter
,
2142 PINDIR_OUTPUT
, &PIN_CATEGORY_CAPTURE
,
2143 chain
->majortype
, FALSE
, 0, &chain
->pCapturePin
);
2145 if (!chain
->pCapturePin
)
2148 if (chain
->type
== video
) {
2149 size
= sizeof(VIDEO_STREAM_CONFIG_CAPS
);
2150 } else if (chain
->type
== audio
) {
2151 size
= sizeof(AUDIO_STREAM_CONFIG_CAPS
);
2153 mp_tmsg(MSGT_TV
, MSGL_ERR
, "tvi_dshow: Unsupported media type passed to %s\n","get_available_formats_pin");
2157 hr
= OLE_CALL_ARGS(chain
->pCapturePin
, EnumMediaTypes
, &pEnum
);
2159 mp_msg(MSGT_TV
, MSGL_DBG4
,
2160 "tvi_dshow: Call to EnumMediaTypes failed (get_available_formats_pin)\n");
2163 for (i
= 0; OLE_CALL_ARGS(pEnum
, Next
, 1, &pmt
, &cFetched
) == S_OK
; i
++) {
2167 OLE_CALL(pEnum
,Reset
);
2170 arpmt
= malloc((count
+ 1) * sizeof(AM_MEDIA_TYPE
*));
2172 return E_OUTOFMEMORY
;
2173 memset(arpmt
, 0, (count
+ 1) * sizeof(AM_MEDIA_TYPE
*));
2177 && OLE_CALL_ARGS(pEnum
, Next
, 1, &(arpmt
[i
]), &cFetched
) == S_OK
;
2180 OLE_RELEASE_SAFE(pEnum
);
2183 pBuf
= malloc((count
+ 1) * sizeof(void *));
2185 for (i
= 0; i
< count
; i
++)
2187 DeleteMediaType(arpmt
[i
]);
2189 return E_OUTOFMEMORY
;
2191 memset(pBuf
, 0, (count
+ 1) * sizeof(void *));
2193 for (i
= 0; i
< count
; i
++) {
2194 pBuf
[i
] = malloc(size
);
2197 memset(pBuf
[i
], 0, size
);
2199 if (chain
->type
== video
) {
2200 pVideoCaps
= (VIDEO_STREAM_CONFIG_CAPS
*) pBuf
[i
];
2201 extract_video_format(arpmt
[i
], NULL
, &p1
, &p2
);
2202 pVideoCaps
->MaxOutputSize
.cx
= pVideoCaps
->MinOutputSize
.cx
=
2204 pVideoCaps
->MaxOutputSize
.cy
= pVideoCaps
->MinOutputSize
.cy
=
2207 pAudioCaps
= (AUDIO_STREAM_CONFIG_CAPS
*) pBuf
[i
];
2208 extract_audio_format(arpmt
[i
], &p1
, &p2
, &p3
);
2209 pAudioCaps
->MaximumSampleFrequency
=
2210 pAudioCaps
->MinimumSampleFrequency
= p1
;
2211 pAudioCaps
->MaximumBitsPerSample
=
2212 pAudioCaps
->MinimumBitsPerSample
= p2
;
2213 pAudioCaps
->MaximumChannels
= pAudioCaps
->MinimumChannels
= p3
;
2218 for (i
= 0; i
< count
; i
++) {
2220 DeleteMediaType(arpmt
[i
]);
2225 return E_OUTOFMEMORY
;
2227 chain
->arpmt
= arpmt
;
2228 chain
->arStreamCaps
= pBuf
;
2234 *---------------------------------------------------------------------------------------
2238 *---------------------------------------------------------------------------------------
2241 * \brief fills given buffer with audio data (usually one block)
2243 * \param priv driver's private data structure
2244 * \param buffer buffer to store data to
2245 * \param len buffer's size in bytes (usually one block size)
2247 * \return audio pts if audio present, 1 - otherwise
2249 static double grab_audio_frame(priv_t
* priv
, char *buffer
, int len
)
2254 grabber_ringbuffer_t
*rb
= priv
->chains
[1]->rbuf
;
2255 grabber_ringbuffer_t
*vrb
= priv
->chains
[0]->rbuf
;
2257 if (!rb
|| !rb
->ringbuffer
)
2260 if(vrb
&& vrb
->tStart
<0){
2261 memset(buffer
,0,len
);
2264 if(vrb
&& rb
->tStart
<0)
2265 rb
->tStart
=vrb
->tStart
;
2267 if (len
< rb
->blocksize
)
2270 bytes
= rb
->blocksize
;
2272 mp_msg(MSGT_TV
, MSGL_DBG3
,"tvi_dshow: FillBuffer (audio) called. %d blocks in buffer, %d bytes requested\n",
2275 mp_msg(MSGT_TV
,MSGL_DBG4
,"tvi_dshow: waiting for frame\n");
2276 for(i
=0;i
<1000 && !rb
->count
;i
++) usec_sleep(1000);
2278 mp_msg(MSGT_TV
,MSGL_DBG4
,"tvi_dshow: waiting timeout\n");
2281 mp_msg(MSGT_TV
,MSGL_DBG4
,"tvi_dshow: got frame!\n");
2284 EnterCriticalSection(rb
->pMutex
);
2285 pts
=rb
->dpts
[rb
->head
]-rb
->tStart
;
2286 memcpy(buffer
, rb
->ringbuffer
[rb
->head
], bytes
);
2287 rb
->head
= (rb
->head
+ 1) % rb
->buffersize
;
2289 LeaveCriticalSection(rb
->pMutex
);
2294 * \brief returns audio frame size
2296 * \param priv driver's private data structure
2298 * \return audio block size if audio enabled and 1 - otherwise
2300 static int get_audio_framesize(priv_t
* priv
)
2302 if (!priv
->chains
[1]->rbuf
)
2303 return 1; //no audio
2304 mp_msg(MSGT_TV
,MSGL_DBG3
,"get_audio_framesize: %d\n",priv
->chains
[1]->rbuf
->blocksize
);
2305 return priv
->chains
[1]->rbuf
->blocksize
;
2308 static int vbi_get_props(priv_t
* priv
,tt_stream_props
* ptsp
)
2311 return TVI_CONTROL_FALSE
;
2317 ptsp
->sampling_rate
=27e6
;
2318 ptsp
->samples_per_line
=720;
2323 ptsp
->bufsize
= ptsp
->samples_per_line
* (ptsp
->count
[0] + ptsp
->count
[1]);
2325 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",
2326 ptsp
->sampling_rate
,
2328 ptsp
->samples_per_line
,
2329 ptsp
->interlaced
?"Yes":"No",
2333 return TVI_CONTROL_TRUE
;
2336 static void vbi_grabber(priv_t
* priv
)
2338 grabber_ringbuffer_t
*rb
= priv
->chains
[2]->rbuf
;
2341 if (!rb
|| !rb
->ringbuffer
)
2344 buf
=calloc(1,rb
->blocksize
);
2345 for(i
=0; i
<23 && rb
->count
; i
++){
2346 memcpy(buf
,rb
->ringbuffer
[rb
->head
],rb
->blocksize
);
2347 teletext_control(priv
->priv_vbi
,TV_VBI_CONTROL_DECODE_PAGE
,&buf
);
2348 rb
->head
= (rb
->head
+ 1) % rb
->buffersize
;
2355 * \brief fills given buffer with video data (usually one frame)
2357 * \param priv driver's private data structure
2358 * \param buffer buffer to store data to
2359 * \param len buffer's size in bytes (usually one frame size)
2361 * \return frame size if video present, 0 - otherwise
2363 static double grab_video_frame(priv_t
* priv
, char *buffer
, int len
)
2368 grabber_ringbuffer_t
*rb
= priv
->chains
[0]->rbuf
;
2370 if (!rb
|| !rb
->ringbuffer
)
2372 if (len
< rb
->blocksize
)
2375 bytes
= rb
->blocksize
;
2377 mp_msg(MSGT_TV
, MSGL_DBG3
,"tvi_dshow: FillBuffer (video) called. %d blocks in buffer, %d bytes requested\n",
2380 mp_msg(MSGT_TV
,MSGL_DBG4
,"tvi_dshow: waiting for frame\n");
2381 for(i
=0;i
<1000 && !rb
->count
;i
++) usec_sleep(1000);
2383 mp_msg(MSGT_TV
,MSGL_DBG4
,"tvi_dshow: waiting timeout\n");
2386 mp_msg(MSGT_TV
,MSGL_DBG4
,"tvi_dshow: got frame!\n");
2388 EnterCriticalSection(rb
->pMutex
);
2390 rb
->tStart
=rb
->dpts
[rb
->head
];
2391 pts
=rb
->dpts
[rb
->head
]-rb
->tStart
;
2392 memcpy(buffer
, rb
->ringbuffer
[rb
->head
], bytes
);
2393 rb
->head
= (rb
->head
+ 1) % rb
->buffersize
;
2395 LeaveCriticalSection(rb
->pMutex
);
2402 * \brief returns frame size
2404 * \param priv driver's private data structure
2406 * \return frame size if video present, 0 - otherwise
2408 static int get_video_framesize(priv_t
* priv
)
2410 // if(!priv->pmtVideo) return 1; //no video
2411 // return priv->pmtVideo->lSampleSize;
2412 if (!priv
->chains
[0]->rbuf
)
2413 return 1; //no video
2414 mp_msg(MSGT_TV
,MSGL_DBG3
,"geT_video_framesize: %d\n",priv
->chains
[0]->rbuf
->blocksize
);
2415 return priv
->chains
[0]->rbuf
->blocksize
;
2419 * \brief calculate audio buffer size
2420 * \param video_buf_size size of video buffer in bytes
2421 * \param video_bitrate video bit rate
2422 * \param audio_bitrate audio bit rate
2423 * \return audio buffer isze in bytes
2425 * \remarks length of video buffer and resulted audio buffer calculated in
2426 * seconds will be the same.
2428 static inline int audio_buf_size_from_video(int video_buf_size
, int video_bitrate
, int audio_bitrate
)
2430 int audio_buf_size
= audio_bitrate
* (video_buf_size
/ video_bitrate
);
2431 mp_msg(MSGT_TV
,MSGL_DBG2
,"tvi_dshow: Audio capture buffer: %d * %d / %d = %d\n",
2432 audio_bitrate
,video_buf_size
,video_bitrate
,audio_buf_size
);
2433 return audio_buf_size
;
2437 * \brief common chain initialization routine
2438 * \param chain chain data structure
2440 * \note pCaptureFilter member should be initialized before call to this routine
2442 static HRESULT
init_chain_common(ICaptureGraphBuilder2
*pBuilder
, chain_t
*chain
)
2447 if(!chain
->pCaptureFilter
)
2450 show_filter_info(chain
->pCaptureFilter
);
2452 hr
= OLE_CALL_ARGS(pBuilder
, FindPin
,
2453 (IUnknown
*) chain
->pCaptureFilter
,
2454 PINDIR_OUTPUT
, chain
->pin_category
,
2455 chain
->majortype
, FALSE
, 0, &chain
->pCapturePin
);
2458 mp_msg(MSGT_TV
,MSGL_DBG2
, "tvi_dshow: FindPin(pCapturePin) call failed. Error:0x%x\n", (unsigned int)hr
);
2462 hr
= OLE_CALL_ARGS(pBuilder
, FindInterface
,
2463 chain
->pin_category
,
2465 chain
->pCaptureFilter
,
2466 &IID_IAMStreamConfig
,
2467 (void **) &(chain
->pStreamConfig
));
2469 chain
->pStreamConfig
= NULL
;
2472 Getting available video formats (last pointer in array will be NULL)
2473 First tryin to call IAMStreamConfig::GetStreamCaos. this will give us additional information such as
2474 min/max picture dimensions, etc. If this call fails trying IPIn::EnumMediaTypes with default
2477 hr
= get_available_formats_stream(chain
);
2479 mp_msg(MSGT_TV
, MSGL_DBG2
, "Unable to use IAMStreamConfig for retriving available formats (Error:0x%x). Using EnumMediaTypes instead\n", (unsigned int)hr
);
2480 hr
= get_available_formats_pin(pBuilder
, chain
);
2485 chain
->nFormatUsed
= 0;
2487 //If argument to CreateMediaType is NULL then result will be NULL too.
2488 chain
->pmt
= CreateMediaType(chain
->arpmt
[0]);
2490 for (i
= 0; chain
->arpmt
[i
]; i
++)
2491 DisplayMediaType("Available format", chain
->arpmt
[i
]);
2496 * \brief build video stream chain in graph
2497 * \param priv private data structure
2499 * \return S_OK if chain was built successfully, apropriate error code otherwise
2501 static HRESULT
build_video_chain(priv_t
*priv
)
2505 if(priv
->chains
[0]->rbuf
)
2508 if (priv
->chains
[0]->pStreamConfig
) {
2509 hr
= OLE_CALL_ARGS(priv
->chains
[0]->pStreamConfig
, SetFormat
, priv
->chains
[0]->pmt
);
2511 mp_tmsg(MSGT_TV
,MSGL_ERR
,"tvi_dshow: Unable to select video format. Error:0x%x\n", (unsigned int)hr
);
2515 priv
->chains
[0]->rbuf
=calloc(1,sizeof(grabber_ringbuffer_t
));
2516 if(!priv
->chains
[0]->rbuf
)
2517 return E_OUTOFMEMORY
;
2519 if (priv
->tv_param
->buffer_size
>= 0) {
2520 priv
->chains
[0]->rbuf
->buffersize
= priv
->tv_param
->buffer_size
;
2522 priv
->chains
[0]->rbuf
->buffersize
= 16;
2525 priv
->chains
[0]->rbuf
->buffersize
*= 1024 * 1024;
2526 hr
=build_sub_graph(priv
, priv
->chains
[0], &PIN_CATEGORY_CAPTURE
);
2528 mp_tmsg(MSGT_TV
, MSGL_ERR
, "tvi_dshow: Unable to build video chain of capture graph. Error:0x%x\n",(unsigned int)hr
);
2535 * \brief build audio stream chain in graph
2536 * \param priv private data structure
2538 * \return S_OK if chain was built successfully, apropriate error code otherwise
2540 static HRESULT
build_audio_chain(priv_t
*priv
)
2544 if(priv
->chains
[1]->rbuf
)
2547 if(priv
->immediate_mode
)
2550 if (priv
->chains
[1]->pStreamConfig
) {
2551 hr
= OLE_CALL_ARGS(priv
->chains
[1]->pStreamConfig
, SetFormat
,
2552 priv
->chains
[1]->pmt
);
2554 mp_tmsg(MSGT_TV
,MSGL_ERR
,"tvi_dshow: Unable to select audio format. Error:0x%x\n", (unsigned int)hr
);
2558 if(priv
->chains
[1]->pmt
){
2559 priv
->chains
[1]->rbuf
=calloc(1,sizeof(grabber_ringbuffer_t
));
2560 if(!priv
->chains
[1]->rbuf
)
2561 return E_OUTOFMEMORY
;
2563 /* let the audio buffer be the same size (in seconds) than video one */
2564 priv
->chains
[1]->rbuf
->buffersize
=audio_buf_size_from_video(
2565 priv
->chains
[0]->rbuf
->buffersize
,
2566 (((VIDEOINFOHEADER
*) priv
->chains
[0]->pmt
->pbFormat
)->dwBitRate
),
2567 (((WAVEFORMATEX
*) (priv
->chains
[1]->pmt
->pbFormat
))->nAvgBytesPerSec
));
2569 hr
=build_sub_graph(priv
, priv
->chains
[1],&PIN_CATEGORY_CAPTURE
);
2571 mp_tmsg(MSGT_TV
, MSGL_ERR
, "tvi_dshow: Unable to build audio chain of capture graph. Error:0x%x\n",(unsigned int)hr
);
2579 * \brief build VBI stream chain in graph
2580 * \param priv private data structure
2582 * \return S_OK if chain was built successfully, apropriate error code otherwise
2584 static HRESULT
build_vbi_chain(priv_t
*priv
)
2588 if(priv
->chains
[2]->rbuf
)
2591 if(priv
->tv_param
->teletext
.device
)
2593 priv
->chains
[2]->rbuf
=calloc(1,sizeof(grabber_ringbuffer_t
));
2594 if(!priv
->chains
[2]->rbuf
)
2595 return E_OUTOFMEMORY
;
2597 init_ringbuffer(priv
->chains
[2]->rbuf
,24,priv
->tsp
.bufsize
);
2599 hr
=build_sub_graph(priv
, priv
->chains
[2],&PIN_CATEGORY_VBI
);
2601 mp_tmsg(MSGT_TV
, MSGL_ERR
, "tvi_dshow: Unable to build VBI chain of capture graph. Error:0x%x\n",(unsigned int)hr
);
2609 * \brief playback/capture real start
2611 * \param priv driver's private data structure
2613 * \return 1 if success, 0 - otherwise
2615 * TODO: move some code from init() here
2617 static int start(priv_t
* priv
)
2621 hr
= build_video_chain(priv
);
2625 hr
= build_audio_chain(priv
);
2629 hr
= build_vbi_chain(priv
);
2634 Graph is ready to capture. Starting graph.
2636 if (mp_msg_test(MSGT_TV
, MSGL_DBG2
)) {
2637 mp_msg(MSGT_TV
, MSGL_DBG2
, "Debug pause 10sec\n");
2638 usec_sleep(10000000);
2639 mp_msg(MSGT_TV
, MSGL_DBG2
, "Debug pause end\n");
2641 if (!priv
->pMediaControl
) {
2642 mp_tmsg(MSGT_TV
,MSGL_ERR
,"tvi_dshow: Unable to get IMediaControl interface. Error:0x%x\n",(unsigned int)E_POINTER
);
2645 hr
= OLE_CALL(priv
->pMediaControl
, Run
);
2647 mp_tmsg(MSGT_TV
,MSGL_ERR
,"tvi_dshow: Unable to start graph! Error:0x%x\n", (unsigned int)hr
);
2650 mp_msg(MSGT_TV
, MSGL_DBG2
, "tvi_dshow: Graph is started.\n");
2657 * \brief driver initialization
2659 * \param priv driver's private data structure
2661 * \return 1 if success, 0 - otherwise
2663 static int init(priv_t
* priv
)
2667 long lInput
, lTunerInput
;
2668 IEnumFilters
*pEnum
;
2669 IBaseFilter
*pFilter
;
2678 priv
->chains
[i
] = calloc(1, sizeof(chain_t
));
2680 priv
->chains
[0]->type
=video
;
2681 priv
->chains
[0]->majortype
=&MEDIATYPE_Video
;
2682 priv
->chains
[0]->pin_category
=&PIN_CATEGORY_CAPTURE
;
2683 priv
->chains
[1]->type
=audio
;
2684 priv
->chains
[1]->majortype
=&MEDIATYPE_Audio
;
2685 priv
->chains
[1]->pin_category
=&PIN_CATEGORY_CAPTURE
;
2686 priv
->chains
[2]->type
=vbi
;
2687 priv
->chains
[2]->majortype
=&MEDIATYPE_VBI
;
2688 priv
->chains
[2]->pin_category
=&PIN_CATEGORY_VBI
;
2691 hr
= CoCreateInstance((GUID
*) & CLSID_FilterGraph
, NULL
,
2692 CLSCTX_INPROC_SERVER
, &IID_IGraphBuilder
,
2693 (void **) &priv
->pGraph
);
2695 mp_msg(MSGT_TV
,MSGL_DBG2
, "tvi_dshow: CoCreateInstance(FilterGraph) call failed. Error:0x%x\n", (unsigned int)hr
);
2699 if (mp_msg_test(MSGT_TV
, MSGL_DBG2
)) {
2700 AddToRot((IUnknown
*) priv
->pGraph
, &(priv
->dwRegister
));
2703 hr
= CoCreateInstance((GUID
*) & CLSID_CaptureGraphBuilder2
, NULL
,
2704 CLSCTX_INPROC_SERVER
, &IID_ICaptureGraphBuilder2
,
2705 (void **) &priv
->pBuilder
);
2707 mp_msg(MSGT_TV
,MSGL_DBG2
, "tvi_dshow: CoCreateInstance(CaptureGraphBuilder) call failed. Error:0x%x\n", (unsigned int)hr
);
2711 hr
= OLE_CALL_ARGS(priv
->pBuilder
, SetFiltergraph
, priv
->pGraph
);
2713 mp_msg(MSGT_TV
,MSGL_ERR
, "tvi_dshow: SetFiltergraph call failed. Error:0x%x\n",(unsigned int)hr
);
2717 mp_msg(MSGT_TV
, MSGL_DBG2
, "tvi_dshow: Searching for available video capture devices\n");
2718 priv
->chains
[0]->pCaptureFilter
= find_capture_device(priv
->dev_index
, &CLSID_VideoInputDeviceCategory
);
2719 if(!priv
->chains
[0]->pCaptureFilter
){
2720 mp_tmsg(MSGT_TV
,MSGL_ERR
, "tvi_dshow: Unable to find video capture device\n");
2723 hr
= OLE_CALL_ARGS(priv
->pGraph
, AddFilter
, priv
->chains
[0]->pCaptureFilter
, NULL
);
2725 mp_msg(MSGT_TV
, MSGL_DBG2
, "tvi_dshow: Unable to add video capture device to Directshow graph. Error:0x%x\n", (unsigned int)hr
);
2728 mp_msg(MSGT_TV
, MSGL_DBG2
, "tvi_dshow: Searching for available audio capture devices\n");
2729 if (priv
->adev_index
!= -1) {
2730 priv
->chains
[1]->pCaptureFilter
= find_capture_device(priv
->adev_index
, &CLSID_AudioInputDeviceCategory
); //output available audio edevices
2731 if(!priv
->chains
[1]->pCaptureFilter
){
2732 mp_tmsg(MSGT_TV
,MSGL_ERR
, "tvi_dshow: Unable to find audio capture device\n");
2736 hr
= OLE_CALL_ARGS(priv
->pGraph
, AddFilter
, priv
->chains
[1]->pCaptureFilter
, NULL
);
2738 mp_msg(MSGT_TV
,MSGL_DBG2
, "tvi_dshow: Unable to add audio capture device to Directshow graph. Error:0x%x\n", (unsigned int)hr
);
2742 hr
= OLE_QUERYINTERFACE(priv
->chains
[0]->pCaptureFilter
, IID_IBaseFilter
, priv
->chains
[1]->pCaptureFilter
);
2744 /* increase refrence counter for capture filter ad store pointer into vbi chain structure too */
2745 hr
= OLE_QUERYINTERFACE(priv
->chains
[0]->pCaptureFilter
, IID_IBaseFilter
, priv
->chains
[2]->pCaptureFilter
);
2747 hr
= OLE_QUERYINTERFACE(priv
->chains
[0]->pCaptureFilter
, IID_IAMVideoProcAmp
,priv
->pVideoProcAmp
);
2748 if (FAILED(hr
) && hr
!= E_NOINTERFACE
)
2749 mp_msg(MSGT_TV
, MSGL_DBG2
, "tvi_dshow: Get IID_IAMVideoProcAmp failed (0x%x).\n", (unsigned int)hr
);
2752 mp_tmsg(MSGT_TV
, MSGL_INFO
, "tvi_dshow: Adjusting of brightness/hue/saturation/contrast is not supported by device\n");
2753 priv
->pVideoProcAmp
= NULL
;
2756 hr
= OLE_CALL_ARGS(priv
->pBuilder
, FindInterface
,
2757 &PIN_CATEGORY_CAPTURE
,
2758 priv
->chains
[0]->majortype
,
2759 priv
->chains
[0]->pCaptureFilter
,
2760 &IID_IAMCrossbar
, (void **) &(priv
->pCrossbar
));
2762 mp_tmsg(MSGT_TV
, MSGL_INFO
, "tvi_dshow: Selection of capture source is not supported by device\n");
2763 priv
->pCrossbar
= NULL
;
2766 if (priv
->tv_param
->amode
>= 0) {
2767 IAMTVAudio
*pTVAudio
;
2768 hr
= OLE_CALL_ARGS(priv
->pBuilder
, FindInterface
, NULL
, NULL
,priv
->chains
[0]->pCaptureFilter
,&IID_IAMTVAudio
, (void *) &pTVAudio
);
2770 switch (priv
->tv_param
->amode
) {
2772 hr
= OLE_CALL_ARGS(pTVAudio
, put_TVAudioMode
, AMTVAUDIO_MODE_MONO
);
2775 hr
= OLE_CALL_ARGS(pTVAudio
, put_TVAudioMode
, AMTVAUDIO_MODE_STEREO
);
2778 hr
= OLE_CALL_ARGS(pTVAudio
, put_TVAudioMode
,
2779 AMTVAUDIO_MODE_LANG_A
);
2782 hr
= OLE_CALL_ARGS(pTVAudio
, put_TVAudioMode
,
2783 AMTVAUDIO_MODE_LANG_B
);
2786 OLE_RELEASE_SAFE(pTVAudio
);
2788 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
);
2792 // Video chain initialization
2793 hr
= init_chain_common(priv
->pBuilder
, priv
->chains
[0]);
2798 Audio chain initialization
2799 Since absent audio stream is not fatal,
2800 at least one NULL pointer should be kept in format arrays
2801 (to avoid another additional check everywhere for array presence).
2803 hr
= init_chain_common(priv
->pBuilder
, priv
->chains
[1]);
2806 mp_msg(MSGT_TV
, MSGL_V
,
2807 "tvi_dshow: Unable to initialize audio chain (Error:0x%lx). Audio disabled\n",
2809 priv
->chains
[1]->arpmt
=calloc(1, sizeof(AM_MEDIA_TYPE
*));
2810 priv
->chains
[1]->arStreamCaps
=calloc(1, sizeof(void*));
2814 VBI chain initialization
2815 Since absent VBI stream is not fatal,
2816 at least one NULL pointer should be kept in format arrays
2817 (to avoid another additional check everywhere for array presence).
2819 hr
= init_chain_common(priv
->pBuilder
, priv
->chains
[2]);
2822 mp_msg(MSGT_TV
, MSGL_V
,
2823 "tvi_dshow: Unable to initialize VBI chain (Error:0x%lx). Teletext disabled\n",
2825 priv
->chains
[2]->arpmt
=calloc(1, sizeof(AM_MEDIA_TYPE
*));
2826 priv
->chains
[2]->arStreamCaps
=calloc(1, sizeof(void*));
2829 if (!priv
->chains
[0]->pStreamConfig
)
2830 mp_tmsg(MSGT_TV
, MSGL_INFO
, "tvi_dshow: Changing video width/height is not supported by device.\n");
2832 if (!priv
->chains
[0]->arpmt
[priv
->chains
[0]->nFormatUsed
]
2833 || !extract_video_format(priv
->chains
[0]->arpmt
[priv
->chains
[0]->nFormatUsed
],
2834 &(priv
->fcc
), &(priv
->width
),
2836 mp_tmsg(MSGT_TV
, MSGL_ERR
, "tvi_dshow: Unable to parse video format structure.\n");
2840 if (priv
->chains
[1]->arpmt
[priv
->chains
[1]->nFormatUsed
]) {
2841 if (!extract_audio_format(priv
->chains
[1]->pmt
, &(priv
->samplerate
), NULL
, NULL
)) {
2842 mp_tmsg(MSGT_TV
, MSGL_ERR
, "tvi_dshow: Unable to parse audio format structure.\n");
2843 DisplayMediaType("audio format failed",priv
->chains
[1]->arpmt
[priv
->chains
[1]->nFormatUsed
]);
2848 hr
= OLE_QUERYINTERFACE(priv
->pGraph
, IID_IMediaControl
,priv
->pMediaControl
);
2850 mp_tmsg(MSGT_TV
,MSGL_ERR
, "tvi_dshow: Unable to get IMediaControl interface. Error:0x%x\n",(unsigned int)hr
);
2853 hr
= OLE_CALL_ARGS(priv
->pBuilder
, FindInterface
,
2854 &PIN_CATEGORY_CAPTURE
, NULL
,
2855 priv
->chains
[0]->pCaptureFilter
,
2856 &IID_IAMTVTuner
, (void **) &(priv
->pTVTuner
));
2858 if (!priv
->pTVTuner
) {
2859 mp_msg(MSGT_TV
, MSGL_DBG2
, "tvi_dshow: Unable to access IAMTVTuner (0x%x)\n", (unsigned int)hr
);
2862 // shows Tuner capabilities
2863 get_capabilities(priv
);
2865 if (priv
->pTVTuner
) {
2866 hr
= OLE_CALL_ARGS(priv
->pTVTuner
, put_CountryCode
,
2867 chanlist2country(priv
->tv_param
->chanlist
));
2869 mp_msg(MSGT_TV
,MSGL_DBG2
, "tvi_dshow: Call to put_CountryCode failed. Error:0x%x\n",(unsigned int)hr
);
2872 hr
= OLE_CALL_ARGS(priv
->pTVTuner
, put_Mode
, AMTUNER_MODE_TV
);
2874 mp_msg(MSGT_TV
,MSGL_DBG2
, "tvi_dshow: Call to put_Mode failed. Error:0x%x\n",(unsigned int)hr
);
2878 hr
= OLE_CALL_ARGS(priv
->pTVTuner
, get_ConnectInput
, &lInput
);
2880 mp_msg(MSGT_TV
,MSGL_DBG2
, "tvi_dshow: Call to get_ConnectInput failed. Error:0x%x\n",(unsigned int)hr
);
2885 lTunerInput
= strstr(priv
->tv_param
->chanlist
, "cable") ? TunerInputCable
: TunerInputAntenna
;
2887 hr
= OLE_CALL_ARGS(priv
->pTVTuner
, put_InputType
, lInput
, lTunerInput
);
2889 mp_msg(MSGT_TV
,MSGL_DBG2
, "tvi_dshow: Call to put_InputType failed. Error:0x%x\n",(unsigned int)hr
);
2896 for VIVO cards we should check if preview pin is available on video capture device.
2897 If it is not, we have to connect Video Port Manager filter to VP pin of capture device filter.
2898 Otherwise we will get 0x8007001f (Device is not functioning properly) when attempting to start graph
2900 hr
= OLE_CALL_ARGS(priv
->pBuilder
, FindPin
,
2901 (IUnknown
*) priv
->chains
[0]->pCaptureFilter
,
2903 &PIN_CATEGORY_VIDEOPORT
, NULL
, FALSE
,
2904 0, (IPin
**) & pVPOutPin
);
2905 if (SUCCEEDED(hr
)) {
2906 hr
= OLE_CALL_ARGS(priv
->pGraph
, Render
, pVPOutPin
);
2907 OLE_RELEASE_SAFE(pVPOutPin
);
2910 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
);
2915 OLE_CALL_ARGS(priv
->pGraph
, EnumFilters
, &pEnum
);
2916 while (OLE_CALL_ARGS(pEnum
, Next
, 1, &pFilter
, NULL
) == S_OK
) {
2917 LPVIDEOWINDOW pVideoWindow
;
2918 hr
= OLE_QUERYINTERFACE(pFilter
, IID_IVideoWindow
, pVideoWindow
);
2921 if(priv
->tv_param
->hidden_vp_renderer
){
2922 OLE_CALL_ARGS(pVideoWindow
,put_Visible
,/* OAFALSE*/ 0);
2923 OLE_CALL_ARGS(pVideoWindow
,put_AutoShow
,/* OAFALSE*/ 0);
2926 OLE_CALL_ARGS(priv
->pGraph
, RemoveFilter
, pFilter
);
2928 OLE_RELEASE_SAFE(pVideoWindow
);
2930 OLE_RELEASE_SAFE(pFilter
);
2932 OLE_RELEASE_SAFE(pEnum
);
2933 if(priv
->tv_param
->system_clock
)
2935 LPREFERENCECLOCK rc
;
2937 hr
= CoCreateInstance((GUID
*) & CLSID_SystemClock
, NULL
,
2938 CLSCTX_INPROC_SERVER
, &IID_IReferenceClock
,
2941 OLE_QUERYINTERFACE(priv
->pBuilder
,IID_IBaseFilter
,pBF
);
2942 OLE_CALL_ARGS(pBF
,SetSyncSource
,rc
);
2944 if(vbi_get_props(priv
,&(priv
->tsp
))!=TVI_CONTROL_TRUE
)
2950 mp_tmsg(MSGT_TV
,MSGL_ERR
, "tvi_dshow: Directshow graph initialization failure.\n");
2957 * \brief chain uninitialization
2958 * \param chain chain data structure
2960 static void destroy_chain(chain_t
*chain
)
2967 OLE_RELEASE_SAFE(chain
->pStreamConfig
);
2968 OLE_RELEASE_SAFE(chain
->pCaptureFilter
);
2969 OLE_RELEASE_SAFE(chain
->pCSGCB
);
2970 OLE_RELEASE_SAFE(chain
->pCapturePin
);
2971 OLE_RELEASE_SAFE(chain
->pSGIn
);
2972 OLE_RELEASE_SAFE(chain
->pSG
);
2973 OLE_RELEASE_SAFE(chain
->pSGF
);
2976 DeleteMediaType(chain
->pmt
);
2979 for (i
= 0; chain
->arpmt
[i
]; i
++) {
2980 DeleteMediaType(chain
->arpmt
[i
]);
2985 if (chain
->arStreamCaps
) {
2986 for (i
= 0; chain
->arStreamCaps
[i
]; i
++) {
2987 free(chain
->arStreamCaps
[i
]);
2989 free(chain
->arStreamCaps
);
2993 destroy_ringbuffer(chain
->rbuf
);
3000 * \brief driver uninitialization
3002 * \param priv driver's private data structure
3006 static int uninit(priv_t
* priv
)
3012 if (priv
->dwRegister
) {
3013 RemoveFromRot(priv
->dwRegister
);
3015 teletext_control(priv
->priv_vbi
,TV_VBI_CONTROL_STOP
,(void*)1);
3016 //stop audio grabber thread
3018 if (priv
->state
&& priv
->pMediaControl
) {
3019 OLE_CALL(priv
->pMediaControl
, Stop
);
3021 OLE_RELEASE_SAFE(priv
->pMediaControl
);
3025 if (priv
->chains
[0]->pCaptureFilter
)
3026 OLE_CALL_ARGS(priv
->pGraph
, RemoveFilter
, priv
->chains
[0]->pCaptureFilter
);
3027 if (priv
->chains
[1]->pCaptureFilter
)
3028 OLE_CALL_ARGS(priv
->pGraph
, RemoveFilter
, priv
->chains
[1]->pCaptureFilter
);
3030 OLE_RELEASE_SAFE(priv
->pCrossbar
);
3031 OLE_RELEASE_SAFE(priv
->pVideoProcAmp
);
3032 OLE_RELEASE_SAFE(priv
->pGraph
);
3033 OLE_RELEASE_SAFE(priv
->pBuilder
);
3034 if(priv
->freq_table
){
3035 priv
->freq_table_len
=-1;
3036 free(priv
->freq_table
);
3037 priv
->freq_table
=NULL
;
3042 destroy_chain(priv
->chains
[i
]);
3043 priv
->chains
[i
] = NULL
;
3050 * \brief driver pre-initialization
3052 * \param device string, containing device name in form "x[.y]", where x is video capture device
3053 * (default: 0, first available); y (if given) sets audio capture device
3055 * \return 1 if success,0 - otherwise
3057 static tvi_handle_t
*tvi_init_dshow(tv_param_t
* tv_param
)
3063 h
= tv_new_handle(sizeof(priv_t
), &functions
);
3069 memset(priv
, 0, sizeof(priv_t
));
3070 priv
->direct_setfreq_call
= 1; //first using direct call. if it fails, workaround will be enabled
3071 priv
->direct_getfreq_call
= 1; //first using direct call. if it fails, workaround will be enabled
3072 priv
->adev_index
= -1;
3073 priv
->freq_table_len
=-1;
3074 priv
->tv_param
=tv_param
;
3076 if (tv_param
->device
) {
3077 if (sscanf(tv_param
->device
, "%d", &a
) == 1) {
3078 priv
->dev_index
= a
;
3080 mp_tmsg(MSGT_TV
, MSGL_ERR
, "tvi_dshow: Wrong device parameter: %s\n", tv_param
->device
);
3084 if (priv
->dev_index
< 0) {
3085 mp_tmsg(MSGT_TV
, MSGL_ERR
, "tvi_dshow: Wrong device index: %d\n", a
);
3090 if (tv_param
->adevice
) {
3091 if (sscanf(tv_param
->adevice
, "%d", &a
) == 1) {
3092 priv
->adev_index
= a
;
3094 mp_tmsg(MSGT_TV
, MSGL_ERR
, "tvi_dshow: Wrong adevice parameter: %s\n", tv_param
->adevice
);
3098 if (priv
->dev_index
< 0) {
3099 mp_tmsg(MSGT_TV
, MSGL_ERR
, "tvi_dshow: Wrong adevice index: %d\n", a
);
3108 * \brief driver's ioctl handler
3110 * \param priv driver's private data structure
3111 * \param cmd ioctl command
3112 * \param arg ioct command's parameter
3114 * \return TVI_CONTROL_TRUE if success
3115 * \return TVI_CONTROL_FALSE if failure
3116 * \return TVI_CONTROL_UNKNOWN if unknowm cmd called
3118 static int control(priv_t
* priv
, int cmd
, void *arg
)
3122 case TVI_CONTROL_VID_SET_FORMAT
:
3126 int result
= TVI_CONTROL_TRUE
;
3129 return TVI_CONTROL_FALSE
;
3132 if(!priv
->chains
[0]->arpmt
)
3133 return TVI_CONTROL_FALSE
;
3134 for (i
= 0; priv
->chains
[0]->arpmt
[i
]; i
++)
3135 if (check_video_format
3136 (priv
->chains
[0]->arpmt
[i
], fcc
, priv
->width
, priv
->height
))
3138 if (!priv
->chains
[0]->arpmt
[i
])
3141 VIDEOINFOHEADER
* Vhdr
= NULL
;
3144 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
));
3146 if (priv
->chains
[0]->arpmt
[0])
3147 Vhdr
= (VIDEOINFOHEADER
*) priv
->chains
[0]->arpmt
[0]->pbFormat
;
3149 if(Vhdr
&& Vhdr
->bmiHeader
.biSizeImage
)
3150 fps
= Vhdr
->dwBitRate
/ (8 * Vhdr
->bmiHeader
.biSizeImage
);
3152 pmt
=create_video_format(fcc
, priv
->width
, priv
->height
, fps
);
3155 mp_msg(MSGT_TV
, MSGL_V
, "tvi_dshow: Unable to create AM_MEDIA_TYPE structure for given format\n");
3156 return TVI_CONTROL_FALSE
;
3158 priv
->chains
[0]->arpmt
=realloc(priv
->chains
[0]->arpmt
, (i
+2)*sizeof(AM_MEDIA_TYPE
*));
3159 priv
->chains
[0]->arpmt
[i
+1] = NULL
;
3160 priv
->chains
[0]->arpmt
[i
] = pmt
;
3162 priv
->chains
[0]->arStreamCaps
=realloc(priv
->chains
[0]->arStreamCaps
, (i
+2)*sizeof(void*));
3163 priv
->chains
[0]->arpmt
[i
+1] = NULL
;
3165 result
= TVI_CONTROL_FALSE
;
3169 tmp
=priv
->chains
[0]->arpmt
[i
];
3170 tmp2
=priv
->chains
[0]->arStreamCaps
[i
];
3173 priv
->chains
[0]->arpmt
[j
] = priv
->chains
[0]->arpmt
[j
-1];
3174 priv
->chains
[0]->arStreamCaps
[j
] = priv
->chains
[0]->arStreamCaps
[j
-1];
3176 priv
->chains
[0]->arpmt
[0] = tmp
;
3177 priv
->chains
[0]->arStreamCaps
[0] = tmp2
;
3179 priv
->chains
[0]->nFormatUsed
= 0;
3181 if (priv
->chains
[0]->pmt
)
3182 DeleteMediaType(priv
->chains
[0]->pmt
);
3183 priv
->chains
[0]->pmt
=
3184 CreateMediaType(priv
->chains
[0]->arpmt
[priv
->chains
[0]->nFormatUsed
]);
3185 DisplayMediaType("VID_SET_FORMAT", priv
->chains
[0]->pmt
);
3187 Setting width & height to preferred by driver values
3189 extract_video_format(priv
->chains
[0]->arpmt
[priv
->chains
[0]->nFormatUsed
],
3190 &(priv
->fcc
), &(priv
->width
),
3194 case TVI_CONTROL_VID_GET_FORMAT
:
3196 if(!priv
->chains
[0]->pmt
)
3197 return TVI_CONTROL_FALSE
;
3199 Build video chain (for video format negotiation).
3200 If this was done before, routine will do nothing.
3202 build_video_chain(priv
);
3203 DisplayMediaType("VID_GET_FORMAT", priv
->chains
[0]->pmt
);
3205 *(int *) arg
= priv
->fcc
;
3206 return TVI_CONTROL_TRUE
;
3208 return TVI_CONTROL_FALSE
;
3210 case TVI_CONTROL_VID_SET_WIDTH
:
3212 VIDEO_STREAM_CONFIG_CAPS
*pCaps
;
3213 VIDEOINFOHEADER
*Vhdr
;
3214 int width
= *(int *) arg
;
3216 return TVI_CONTROL_FALSE
;
3218 pCaps
= priv
->chains
[0]->arStreamCaps
[priv
->chains
[0]->nFormatUsed
];
3220 return TVI_CONTROL_FALSE
;
3221 if (width
< pCaps
->MinOutputSize
.cx
3222 || width
> pCaps
->MaxOutputSize
.cx
)
3223 return TVI_CONTROL_FALSE
;
3225 if (width
% pCaps
->OutputGranularityX
)
3226 return TVI_CONTROL_FALSE
;
3228 if (!priv
->chains
[0]->pmt
|| !priv
->chains
[0]->pmt
->pbFormat
)
3229 return TVI_CONTROL_FALSE
;
3230 Vhdr
= (VIDEOINFOHEADER
*) priv
->chains
[0]->pmt
->pbFormat
;
3231 Vhdr
->bmiHeader
.biWidth
= width
;
3232 priv
->chains
[0]->pmt
->lSampleSize
= Vhdr
->bmiHeader
.biSizeImage
=
3233 labs(Vhdr
->bmiHeader
.biBitCount
* Vhdr
->bmiHeader
.biWidth
*
3234 Vhdr
->bmiHeader
.biHeight
) >> 3;
3236 priv
->width
= width
;
3238 return TVI_CONTROL_TRUE
;
3240 case TVI_CONTROL_VID_GET_WIDTH
:
3243 *(int *) arg
= priv
->width
;
3244 return TVI_CONTROL_TRUE
;
3246 return TVI_CONTROL_FALSE
;
3248 case TVI_CONTROL_VID_CHK_WIDTH
:
3250 VIDEO_STREAM_CONFIG_CAPS
*pCaps
;
3251 int width
= *(int *) arg
;
3252 pCaps
= priv
->chains
[0]->arStreamCaps
[priv
->chains
[0]->nFormatUsed
];
3254 return TVI_CONTROL_FALSE
;
3255 if (width
< pCaps
->MinOutputSize
.cx
3256 || width
> pCaps
->MaxOutputSize
.cx
)
3257 return TVI_CONTROL_FALSE
;
3259 if (width
% pCaps
->OutputGranularityX
)
3260 return TVI_CONTROL_FALSE
;
3261 return TVI_CONTROL_TRUE
;
3263 case TVI_CONTROL_VID_SET_HEIGHT
:
3265 VIDEO_STREAM_CONFIG_CAPS
*pCaps
;
3266 VIDEOINFOHEADER
*Vhdr
;
3267 int height
= *(int *) arg
;
3269 return TVI_CONTROL_FALSE
;
3271 pCaps
= priv
->chains
[0]->arStreamCaps
[priv
->chains
[0]->nFormatUsed
];
3273 return TVI_CONTROL_FALSE
;
3274 if (height
< pCaps
->MinOutputSize
.cy
3275 || height
> pCaps
->MaxOutputSize
.cy
)
3276 return TVI_CONTROL_FALSE
;
3278 if (height
% pCaps
->OutputGranularityY
)
3279 return TVI_CONTROL_FALSE
;
3281 if (!priv
->chains
[0]->pmt
|| !priv
->chains
[0]->pmt
->pbFormat
)
3282 return TVI_CONTROL_FALSE
;
3283 Vhdr
= (VIDEOINFOHEADER
*) priv
->chains
[0]->pmt
->pbFormat
;
3285 if (Vhdr
->bmiHeader
.biHeight
< 0)
3286 Vhdr
->bmiHeader
.biHeight
= -height
;
3288 Vhdr
->bmiHeader
.biHeight
= height
;
3289 priv
->chains
[0]->pmt
->lSampleSize
= Vhdr
->bmiHeader
.biSizeImage
=
3290 labs(Vhdr
->bmiHeader
.biBitCount
* Vhdr
->bmiHeader
.biWidth
*
3291 Vhdr
->bmiHeader
.biHeight
) >> 3;
3293 priv
->height
= height
;
3294 return TVI_CONTROL_TRUE
;
3296 case TVI_CONTROL_VID_GET_HEIGHT
:
3299 *(int *) arg
= priv
->height
;
3300 return TVI_CONTROL_TRUE
;
3302 return TVI_CONTROL_FALSE
;
3304 case TVI_CONTROL_VID_CHK_HEIGHT
:
3306 VIDEO_STREAM_CONFIG_CAPS
*pCaps
;
3307 int height
= *(int *) arg
;
3308 pCaps
= priv
->chains
[0]->arStreamCaps
[priv
->chains
[0]->nFormatUsed
];
3310 return TVI_CONTROL_FALSE
;
3311 if (height
< pCaps
->MinOutputSize
.cy
3312 || height
> pCaps
->MaxOutputSize
.cy
)
3313 return TVI_CONTROL_FALSE
;
3315 if (height
% pCaps
->OutputGranularityY
)
3316 return TVI_CONTROL_FALSE
;
3318 return TVI_CONTROL_TRUE
;
3320 case TVI_CONTROL_IS_AUDIO
:
3321 if (!priv
->chains
[1]->pmt
)
3322 return TVI_CONTROL_FALSE
;
3324 return TVI_CONTROL_TRUE
;
3325 case TVI_CONTROL_IS_VIDEO
:
3326 return TVI_CONTROL_TRUE
;
3327 case TVI_CONTROL_AUD_GET_FORMAT
:
3329 *(int *) arg
= AF_FORMAT_S16_LE
;
3330 if (!priv
->chains
[1]->pmt
)
3331 return TVI_CONTROL_FALSE
;
3333 return TVI_CONTROL_TRUE
;
3335 case TVI_CONTROL_AUD_GET_CHANNELS
:
3337 *(int *) arg
= priv
->channels
;
3338 if (!priv
->chains
[1]->pmt
)
3339 return TVI_CONTROL_FALSE
;
3341 return TVI_CONTROL_TRUE
;
3343 case TVI_CONTROL_AUD_SET_SAMPLERATE
:
3347 return TVI_CONTROL_FALSE
;
3348 if (!priv
->chains
[1]->arpmt
[0])
3349 return TVI_CONTROL_FALSE
;
3351 samplerate
= *(int *) arg
;
3353 for (i
= 0; priv
->chains
[1]->arpmt
[i
]; i
++)
3354 if (check_audio_format
3355 (priv
->chains
[1]->arpmt
[i
], samplerate
, 16, priv
->channels
))
3357 if (!priv
->chains
[1]->arpmt
[i
]) {
3358 //request not found. failing back to first available
3359 mp_tmsg(MSGT_TV
, MSGL_WARN
, "tvi_dshow: Samplerate %d is not supported by device. Failing back to first available.\n", samplerate
);
3362 if (priv
->chains
[1]->pmt
)
3363 DeleteMediaType(priv
->chains
[1]->pmt
);
3364 priv
->chains
[1]->pmt
= CreateMediaType(priv
->chains
[1]->arpmt
[i
]);
3365 extract_audio_format(priv
->chains
[1]->arpmt
[i
], &(priv
->samplerate
),
3366 NULL
, &(priv
->channels
));
3367 return TVI_CONTROL_TRUE
;
3369 case TVI_CONTROL_AUD_GET_SAMPLERATE
:
3371 *(int *) arg
= priv
->samplerate
;
3372 if (!priv
->samplerate
)
3373 return TVI_CONTROL_FALSE
;
3374 if (!priv
->chains
[1]->pmt
)
3375 return TVI_CONTROL_FALSE
;
3377 return TVI_CONTROL_TRUE
;
3379 case TVI_CONTROL_AUD_GET_SAMPLESIZE
:
3382 if (!priv
->chains
[1]->pmt
)
3383 return TVI_CONTROL_FALSE
;
3384 if (!priv
->chains
[1]->pmt
->pbFormat
)
3385 return TVI_CONTROL_FALSE
;
3386 pWF
= (WAVEFORMATEX
*) priv
->chains
[1]->pmt
->pbFormat
;
3387 *(int *) arg
= pWF
->wBitsPerSample
/ 8;
3388 return TVI_CONTROL_TRUE
;
3390 case TVI_CONTROL_IS_TUNER
:
3392 if (!priv
->pTVTuner
)
3393 return TVI_CONTROL_FALSE
;
3395 return TVI_CONTROL_TRUE
;
3397 case TVI_CONTROL_TUN_SET_NORM
:
3399 IAMAnalogVideoDecoder
*pVD
;
3406 if (i
< 0 || i
>= tv_available_norms_count
)
3407 return TVI_CONTROL_FALSE
;
3408 lAnalogFormat
= tv_norms
[tv_available_norms
[i
]].index
;
3410 hr
= OLE_QUERYINTERFACE(priv
->chains
[0]->pCaptureFilter
,IID_IAMAnalogVideoDecoder
, pVD
);
3412 return TVI_CONTROL_FALSE
;
3413 hr
= OLE_CALL_ARGS(pVD
, put_TVFormat
, lAnalogFormat
);
3414 OLE_RELEASE_SAFE(pVD
);
3416 return TVI_CONTROL_FALSE
;
3418 return TVI_CONTROL_TRUE
;
3420 case TVI_CONTROL_TUN_GET_NORM
:
3425 IAMAnalogVideoDecoder
*pVD
;
3427 hr
= OLE_QUERYINTERFACE(priv
->chains
[0]->pCaptureFilter
,IID_IAMAnalogVideoDecoder
, pVD
);
3429 hr
= OLE_CALL_ARGS(pVD
, get_TVFormat
, &lAnalogFormat
);
3430 OLE_RELEASE_SAFE(pVD
);
3433 if (FAILED(hr
)) { //trying another method
3434 if (!priv
->pTVTuner
)
3435 return TVI_CONTROL_FALSE
;
3436 hr
=OLE_CALL_ARGS(priv
->pTVTuner
, get_TVFormat
, &lAnalogFormat
);
3438 return TVI_CONTROL_FALSE
;
3440 for (i
= 0; i
< tv_available_norms_count
; i
++) {
3441 if (tv_norms
[tv_available_norms
[i
]].index
== lAnalogFormat
) {
3442 *(int *) arg
= i
+ 1;
3443 return TVI_CONTROL_TRUE
;
3446 return TVI_CONTROL_FALSE
;
3448 case TVI_CONTROL_SPC_GET_NORMID
:
3451 if (!priv
->pTVTuner
)
3452 return TVI_CONTROL_FALSE
;
3453 for (i
= 0; i
< tv_available_norms_count
; i
++) {
3455 (tv_norms
[tv_available_norms
[i
]].name
, (char *) arg
)) {
3456 *(int *) arg
= i
+ 1;
3457 return TVI_CONTROL_TRUE
;
3460 return TVI_CONTROL_FALSE
;
3462 case TVI_CONTROL_SPC_SET_INPUT
:
3464 return set_crossbar_input(priv
, *(int *) arg
);
3466 case TVI_CONTROL_TUN_GET_FREQ
:
3468 unsigned long lFreq
;
3470 if (!priv
->pTVTuner
)
3471 return TVI_CONTROL_FALSE
;
3473 ret
= get_frequency(priv
, &lFreq
);
3474 lFreq
= lFreq
/ (1000000/16); //convert from Hz to 1/16 MHz units
3476 *(unsigned long *) arg
= lFreq
;
3479 case TVI_CONTROL_TUN_SET_FREQ
:
3481 unsigned long nFreq
= *(unsigned long *) arg
;
3482 if (!priv
->pTVTuner
)
3483 return TVI_CONTROL_FALSE
;
3485 nFreq
= (1000000/16) * nFreq
; //convert from 1/16 MHz units to Hz
3486 return set_frequency(priv
, nFreq
);
3488 case TVI_CONTROL_VID_SET_HUE
:
3489 return set_control(priv
, VideoProcAmp_Hue
, *(int *) arg
);
3490 case TVI_CONTROL_VID_GET_HUE
:
3491 return get_control(priv
, VideoProcAmp_Hue
, (int *) arg
);
3492 case TVI_CONTROL_VID_SET_CONTRAST
:
3493 return set_control(priv
, VideoProcAmp_Contrast
, *(int *) arg
);
3494 case TVI_CONTROL_VID_GET_CONTRAST
:
3495 return get_control(priv
, VideoProcAmp_Contrast
, (int *) arg
);
3496 case TVI_CONTROL_VID_SET_SATURATION
:
3497 return set_control(priv
, VideoProcAmp_Saturation
, *(int *) arg
);
3498 case TVI_CONTROL_VID_GET_SATURATION
:
3499 return get_control(priv
, VideoProcAmp_Saturation
, (int *) arg
);
3500 case TVI_CONTROL_VID_SET_BRIGHTNESS
:
3501 return set_control(priv
, VideoProcAmp_Brightness
, *(int *) arg
);
3502 case TVI_CONTROL_VID_GET_BRIGHTNESS
:
3503 return get_control(priv
, VideoProcAmp_Brightness
, (int *) arg
);
3505 case TVI_CONTROL_VID_GET_FPS
:
3507 VIDEOINFOHEADER
*Vhdr
;
3508 if (!priv
->chains
[0]->pmt
)
3509 return TVI_CONTROL_FALSE
;
3510 if (!priv
->chains
[0]->pmt
->pbFormat
)
3511 return TVI_CONTROL_FALSE
;
3512 Vhdr
= (VIDEOINFOHEADER
*) priv
->chains
[0]->pmt
->pbFormat
;
3514 (1.0 * Vhdr
->dwBitRate
) / (Vhdr
->bmiHeader
.biSizeImage
* 8);
3515 return TVI_CONTROL_TRUE
;
3517 case TVI_CONTROL_IMMEDIATE
:
3518 priv
->immediate_mode
= 1;
3519 return TVI_CONTROL_TRUE
;
3520 case TVI_CONTROL_VBI_INIT
:
3524 if(teletext_control(NULL
,TV_VBI_CONTROL_START
,&ptr
)==VBI_CONTROL_TRUE
)
3527 priv
->priv_vbi
=NULL
;
3528 return TVI_CONTROL_TRUE
;
3530 case TVI_CONTROL_GET_VBI_PTR
:
3531 *(void **)arg
=priv
->priv_vbi
;
3532 return TVI_CONTROL_TRUE
;
3534 return TVI_CONTROL_UNKNOWN
;