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"
82 #include "osdep/timer.h"
87 #include "frequencies.h"
90 #include "tvi_dshow.h"
94 #define STDCALL __stdcall
97 static tvi_handle_t
*tvi_init_dshow(tv_param_t
* tv_param
);
100 *---------------------------------------------------------------------------------------
104 *---------------------------------------------------------------------------------------
107 information about this file
109 const tvi_info_t tvi_info_dshow
= {
113 "Vladimir Voroshilov",
114 "Very experimental!! Use with caution"
119 ringbuffer related info
122 CRITICAL_SECTION
*pMutex
; ///< pointer to critical section (mutex)
123 char **ringbuffer
; ///< ringbuffer array
124 double*dpts
; ///< samples' timestamps
126 int buffersize
; ///< size of buffer in blocks
127 int blocksize
; ///< size of individual block
128 int head
; ///< index of first valid sample
129 int tail
; ///< index of last valid sample
130 int count
; ///< count of valid samples in ringbuffer
131 double tStart
; ///< pts of first sample (first sample should have pts 0)
132 } grabber_ringbuffer_t
;
134 typedef enum { unknown
, video
, audio
, vbi
} stream_type
;
137 CSampleGrabberCD definition
139 typedef struct CSampleGrabberCB
{
140 ISampleGrabberCBVtbl
*lpVtbl
;
143 grabber_ringbuffer_t
*pbuf
;
147 Chain related structure
150 stream_type type
; ///< stream type
151 const GUID
* majortype
; ///< GUID of major mediatype (video/audio/vbi)
152 const GUID
* pin_category
; ///< pin category (pointer to one of PIN_CATEGORY_*)
154 IBaseFilter
*pCaptureFilter
; ///< capture device filter
155 IAMStreamConfig
*pStreamConfig
; ///< for configuring stream
156 ISampleGrabber
*pSG
; ///< ISampleGrabber interface of SampleGrabber filter
157 IBaseFilter
*pSGF
; ///< IBaseFilter interface of SampleGrabber filter
158 IPin
*pCapturePin
; ///< output capture pin
159 IPin
*pSGIn
; ///< input pin of SampleGrabber filter
161 grabber_ringbuffer_t
*rbuf
; ///< sample frabber data
162 CSampleGrabberCB
* pCSGCB
; ///< callback object
164 AM_MEDIA_TYPE
*pmt
; ///< stream properties.
165 int nFormatUsed
; ///< index of used format
166 AM_MEDIA_TYPE
**arpmt
; ///< available formats
167 void** arStreamCaps
; ///< VIDEO_STREAM_CONFIG_CAPS or AUDIO_STREAM_CONFIG_CAPS
171 int dev_index
; ///< capture device index in device list (defaul: 0, first available device)
172 int adev_index
; ///< audio capture device index in device list (default: -1, not used)
173 int immediate_mode
; ///< immediate mode (no sound capture)
174 int state
; ///< state: 1-filter graph running, 0-filter graph stopped
175 int direct_setfreq_call
; ///< 0-find nearest channels from system channel list(workaround),1-direct call to set frequency
176 int direct_getfreq_call
; ///< 0-find frequncy from frequency table (workaround),1-direct call to get frequency
178 int fcc
; ///< used video format code (FourCC)
179 int width
; ///< picture width (default: auto)
180 int height
; ///< picture height (default: auto)
182 int channels
; ///< number of audio channels (default: auto)
183 int samplerate
; ///< audio samplerate (default: auto)
185 long *freq_table
; ///< frequency table (in Hz)
186 int freq_table_len
; ///< length of freq table
187 int first_channel
; ///< channel number of first entry in freq table
188 int input
; ///< used input
190 chain_t
* chains
[3]; ///< chains' data (0-video, 1-audio, 2-vbi)
192 IAMTVTuner
*pTVTuner
; ///< interface for tuner device
193 IGraphBuilder
*pGraph
; ///< filter graph
194 ICaptureGraphBuilder2
*pBuilder
; ///< graph builder
195 IMediaControl
*pMediaControl
; ///< interface for controlling graph (start, stop,...)
196 IAMVideoProcAmp
*pVideoProcAmp
; ///< for adjusting hue,saturation,etc
197 IAMCrossbar
*pCrossbar
; ///< for selecting input (Tuner,Composite,S-Video,...)
198 DWORD dwRegister
; ///< allow graphedit to connect to our graph
199 void *priv_vbi
; ///< private VBI data structure
200 tt_stream_props tsp
; ///< data for VBI initialization
202 tv_param_t
* tv_param
; ///< TV parameters
208 country table entry structure (for loading freq table stored in kstvtuner.ax
211 structure have to be 2-byte aligned and have 10-byte length!!
213 typedef struct __attribute__((__packed__
)) {
214 WORD CountryCode
; ///< Country code
215 WORD CableFreqTable
; ///< index of resource with frequencies for cable channels
216 WORD BroadcastFreqTable
; ///< index of resource with frequencies for broadcast channels
217 DWORD VideoStandard
; ///< used video standard
220 information about image formats
223 uint32_t fmt
; ///< FourCC
224 const GUID
*subtype
; ///< DirectShow's subtype
225 int nBits
; ///< number of bits
226 int nCompression
; ///< complression
227 int tail
; ///< number of additional bytes followed VIDEOINFOHEADER structure
231 *---------------------------------------------------------------------------------------
233 * Methods forward declaration
235 *---------------------------------------------------------------------------------------
237 static HRESULT
init_ringbuffer(grabber_ringbuffer_t
* rb
, int buffersize
,
239 static HRESULT
show_filter_info(IBaseFilter
* pFilter
);
241 //defined in current MinGW release
242 HRESULT STDCALL
GetRunningObjectTable(DWORD
, IRunningObjectTable
**);
243 HRESULT STDCALL
CreateItemMoniker(LPCOLESTR
, LPCOLESTR
, IMoniker
**);
245 static CSampleGrabberCB
*CSampleGrabberCB_Create(grabber_ringbuffer_t
*
247 static int set_crossbar_input(priv_t
* priv
, int input
);
248 static int subtype2imgfmt(const GUID
* subtype
);
251 *---------------------------------------------------------------------------------------
253 * Global constants and variables
255 *---------------------------------------------------------------------------------------
258 lookup tables for physical connector types
260 static const struct {
263 } tv_physcon_types
[]={
264 {PhysConn_Video_Tuner
, "Tuner" },
265 {PhysConn_Video_Composite
, "Composite" },
266 {PhysConn_Video_SVideo
, "S-Video" },
267 {PhysConn_Video_RGB
, "RGB" },
268 {PhysConn_Video_YRYBY
, "YRYBY" },
269 {PhysConn_Video_SerialDigital
, "SerialDigital" },
270 {PhysConn_Video_ParallelDigital
, "ParallelDigital"},
271 {PhysConn_Video_VideoDecoder
, "VideoDecoder" },
272 {PhysConn_Video_VideoEncoder
, "VideoEncoder" },
273 {PhysConn_Video_SCART
, "SCART" },
274 {PhysConn_Video_Black
, "Blaack" },
275 {PhysConn_Audio_Tuner
, "Tuner" },
276 {PhysConn_Audio_Line
, "Line" },
277 {PhysConn_Audio_Mic
, "Mic" },
278 {PhysConn_Audio_AESDigital
, "AESDiital" },
279 {PhysConn_Audio_SPDIFDigital
, "SPDIFDigital" },
280 {PhysConn_Audio_AudioDecoder
, "AudioDecoder" },
281 {PhysConn_Audio_SCSI
, "SCSI" },
282 {PhysConn_Video_SCSI
, "SCSI" },
283 {PhysConn_Audio_AUX
, "AUX" },
284 {PhysConn_Video_AUX
, "AUX" },
285 {PhysConn_Audio_1394
, "1394" },
286 {PhysConn_Video_1394
, "1394" },
287 {PhysConn_Audio_USB
, "USB" },
288 {PhysConn_Video_USB
, "USB" },
292 static const struct {
295 } tv_chanlist2country
[]={
307 //directshow table uses eastern europe freq table for russia
309 //directshow table uses western europe freq table for germany
320 array, contains information about various supported (i hope) image formats
322 static const img_fmt img_fmt_list
[] = {
323 {IMGFMT_YUY2
, &MEDIASUBTYPE_YUY2
, 16, IMGFMT_YUY2
, 0},
324 {IMGFMT_YV12
, &MEDIASUBTYPE_YV12
, 12, IMGFMT_YV12
, 0},
325 {IMGFMT_IYUV
, &MEDIASUBTYPE_IYUV
, 12, IMGFMT_IYUV
, 0},
326 {IMGFMT_I420
, &MEDIASUBTYPE_I420
, 12, IMGFMT_I420
, 0},
327 {IMGFMT_UYVY
, &MEDIASUBTYPE_UYVY
, 16, IMGFMT_UYVY
, 0},
328 {IMGFMT_YVYU
, &MEDIASUBTYPE_YVYU
, 16, IMGFMT_YVYU
, 0},
329 {IMGFMT_YVU9
, &MEDIASUBTYPE_YVU9
, 9, IMGFMT_YVU9
, 0},
330 {IMGFMT_BGR32
, &MEDIASUBTYPE_RGB32
, 32, 0, 0},
331 {IMGFMT_BGR24
, &MEDIASUBTYPE_RGB24
, 24, 0, 0},
332 {IMGFMT_BGR16
, &MEDIASUBTYPE_RGB565
, 16, 3, 12},
333 {IMGFMT_BGR15
, &MEDIASUBTYPE_RGB555
, 16, 3, 12},
334 {0, &GUID_NULL
, 0, 0, 0}
337 #define TV_NORMS_COUNT 19
338 static const struct {
341 } tv_norms
[TV_NORMS_COUNT
] = {
343 AnalogVideo_NTSC_M
, "ntsc-m"}, {
344 AnalogVideo_NTSC_M_J
, "ntsc-mj"}, {
345 AnalogVideo_NTSC_433
, "ntsc-433"}, {
346 AnalogVideo_PAL_B
, "pal-b"}, {
347 AnalogVideo_PAL_D
, "pal-d"}, {
348 AnalogVideo_PAL_G
, "pal-g"}, {
349 AnalogVideo_PAL_H
, "pal-h"}, {
350 AnalogVideo_PAL_I
, "pal-i"}, {
351 AnalogVideo_PAL_M
, "pal-m"}, {
352 AnalogVideo_PAL_N
, "pal-n"}, {
353 AnalogVideo_PAL_60
, "pal-60"}, {
354 AnalogVideo_SECAM_B
, "secam-b"}, {
355 AnalogVideo_SECAM_D
, "secam-d"}, {
356 AnalogVideo_SECAM_G
, "secam-g"}, {
357 AnalogVideo_SECAM_H
, "secam-h"}, {
358 AnalogVideo_SECAM_K
, "secam-k"}, {
359 AnalogVideo_SECAM_K1
, "secam-k1"}, {
360 AnalogVideo_SECAM_L
, "secam-l"}, {
361 AnalogVideo_SECAM_L1
, "secam-l1"}
363 static long tv_available_norms
[TV_NORMS_COUNT
];
364 static int tv_available_norms_count
= 0;
367 static long *tv_available_inputs
;
368 static int tv_available_inputs_count
= 0;
371 *---------------------------------------------------------------------------------------
373 * Various GUID definitions
375 *---------------------------------------------------------------------------------------
377 // selectany can not be used with "static", fixes compilation with mingw-w64
378 #undef DECLSPEC_SELECTANY
379 #define DECLSPEC_SELECTANY
380 /// CLSID definitions (used for CoCreateInstance call)
381 #define CLSID_SampleGrabber MP_CLSID_SampleGrabber
382 static DEFINE_GUID(CLSID_SampleGrabber
, 0xC1F400A0, 0x3F08, 0x11d3, 0x9F, 0x0B,
383 0x00, 0x60, 0x08, 0x03, 0x9E, 0x37);
384 #define CLSID_NullRenderer MP_CLSID_NullRenderer
385 static DEFINE_GUID(CLSID_NullRenderer
, 0xC1F400A4, 0x3F08, 0x11d3, 0x9F, 0x0B,
386 0x00, 0x60, 0x08, 0x03, 0x9E, 0x37);
387 #define CLSID_SystemDeviceEnum MP_CLSID_SystemDeviceEnum
388 static DEFINE_GUID(CLSID_SystemDeviceEnum
, 0x62BE5D10, 0x60EB, 0x11d0, 0xBD, 0x3B,
389 0x00, 0xA0, 0xC9, 0x11, 0xCE, 0x86);
390 #define CLSID_CaptureGraphBuilder2 MP_CLSID_CaptureGraphBuilder2
391 static DEFINE_GUID(CLSID_CaptureGraphBuilder2
, 0xBF87B6E1, 0x8C27, 0x11d0, 0xB3,
392 0xF0, 0x00, 0xAA, 0x00, 0x37, 0x61, 0xC5);
393 #define CLSID_VideoInputDeviceCategory MP_CLSID_VideoInputDeviceCategory
394 static DEFINE_GUID(CLSID_VideoInputDeviceCategory
, 0x860BB310, 0x5D01, 0x11d0,
395 0xBD, 0x3B, 0x00, 0xA0, 0xC9, 0x11, 0xCE, 0x86);
396 #define CLSID_AudioInputDeviceCategory MP_CLSID_AudioInputDeviceCategory
397 static DEFINE_GUID(CLSID_AudioInputDeviceCategory
, 0x33d9a762, 0x90c8, 0x11d0,
398 0xbd, 0x43, 0x00, 0xa0, 0xc9, 0x11, 0xce, 0x86);
399 #define CLSID_FilterGraph MP_CLSID_FilterGraph
400 static DEFINE_GUID(CLSID_FilterGraph
, 0xe436ebb3, 0x524f, 0x11ce, 0x9f, 0x53,
401 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70);
402 #define CLSID_SystemClock MP_CLSID_SystemClock
403 static DEFINE_GUID(CLSID_SystemClock
, 0xe436ebb1, 0x524f, 0x11ce, 0x9f, 0x53,
404 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70);
406 #define CLSID_CaptureGraphBuilder MP_CLSID_CaptureGraphBuilder
407 static DEFINE_GUID(CLSID_CaptureGraphBuilder
, 0xBF87B6E0, 0x8C27, 0x11d0, 0xB3,
408 0xF0, 0x00, 0xAA, 0x00, 0x37, 0x61, 0xC5);
409 #define CLSID_VideoPortManager MP_CLSID_VideoPortManager
410 static DEFINE_GUID(CLSID_VideoPortManager
, 0x6f26a6cd, 0x967b, 0x47fd, 0x87, 0x4a,
411 0x7a, 0xed, 0x2c, 0x9d, 0x25, 0xa2);
412 #define IID_IPin MP_IID_IPin
413 static DEFINE_GUID(IID_IPin
, 0x56a86891, 0x0ad4, 0x11ce, 0xb0, 0x3a, 0x00, 0x20,
414 0xaf, 0x0b, 0xa7, 0x70);
415 #define IID_ICaptureGraphBuilder MP_IID_ICaptureGraphBuilder
416 static DEFINE_GUID(IID_ICaptureGraphBuilder
, 0xbf87b6e0, 0x8c27, 0x11d0, 0xb3,
417 0xf0, 0x00, 0xaa, 0x00, 0x37, 0x61, 0xc5);
418 #define IID_IFilterGraph MP_IID_IFilterGraph
419 static DEFINE_GUID(IID_IFilterGraph
, 0x56a8689f, 0x0ad4, 0x11ce, 0xb0, 0x3a, 0x00,
420 0x20, 0xaf, 0x0b, 0xa7, 0x70);
421 #define PIN_CATEGORY_PREVIEW MP_PIN_CATEGORY_PREVIEW
422 static DEFINE_GUID(PIN_CATEGORY_PREVIEW
, 0xfb6c4282, 0x0353, 0x11d1, 0x90, 0x5f,
423 0x00, 0x00, 0xc0, 0xcc, 0x16, 0xba);
426 /// IID definitions (used for QueryInterface call)
427 #define IID_IReferenceClock MP_IID_IReferenceClock
428 static DEFINE_GUID(IID_IReferenceClock
, 0x56a86897, 0x0ad4, 0x11ce, 0xb0, 0x3a,
429 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70);
430 #define IID_IAMBufferNegotiation MP_IID_IAMBufferNegotiation
431 static DEFINE_GUID(IID_IAMBufferNegotiation
, 0x56ED71A0, 0xAF5F, 0x11D0, 0xB3, 0xF0,
432 0x00, 0xAA, 0x00, 0x37, 0x61, 0xC5);
433 #define IID_IKsPropertySet MP_IID_IKsPropertySet
434 static DEFINE_GUID(IID_IKsPropertySet
, 0x31efac30, 0x515c, 0x11d0, 0xa9, 0xaa,
435 0x00, 0xaa, 0x00, 0x61, 0xbe, 0x93);
436 #define IID_ISampleGrabber MP_IID_ISampleGrabber
437 static DEFINE_GUID(IID_ISampleGrabber
, 0x6B652FFF, 0x11FE, 0x4fce, 0x92, 0xAD,
438 0x02, 0x66, 0xB5, 0xD7, 0xC7, 0x8F);
439 #define IID_ISampleGrabberCB MP_IID_ISampleGrabberCB
440 static DEFINE_GUID(IID_ISampleGrabberCB
, 0x0579154A, 0x2B53, 0x4994, 0xB0, 0xD0,
441 0xE7, 0x73, 0x14, 0x8E, 0xFF, 0x85);
442 #define IID_ICaptureGraphBuilder2 MP_IID_ICaptureGraphBuilder2
443 static DEFINE_GUID(IID_ICaptureGraphBuilder2
, 0x93e5a4e0, 0x2d50, 0x11d2, 0xab,
444 0xfa, 0x00, 0xa0, 0xc9, 0xc6, 0xe3, 0x8d);
445 #define IID_ICreateDevEnum MP_IID_ICreateDevEnum
446 static DEFINE_GUID(IID_ICreateDevEnum
, 0x29840822, 0x5b84, 0x11d0, 0xbd, 0x3b,
447 0x00, 0xa0, 0xc9, 0x11, 0xce, 0x86);
448 #define IID_IGraphBuilder MP_IID_IGraphBuilder
449 static DEFINE_GUID(IID_IGraphBuilder
, 0x56a868a9, 0x0ad4, 0x11ce, 0xb0, 0x3a,
450 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70);
451 #define IID_IAMVideoProcAmp MP_IID_IAMVideoProcAmp
452 static DEFINE_GUID(IID_IAMVideoProcAmp
, 0xC6E13360, 0x30AC, 0x11d0, 0xA1, 0x8C,
453 0x00, 0xA0, 0xC9, 0x11, 0x89, 0x56);
454 #define IID_IVideoWindow MP_IID_IVideoWindow
455 static DEFINE_GUID(IID_IVideoWindow
, 0x56a868b4, 0x0ad4, 0x11ce, 0xb0, 0x3a, 0x00,
456 0x20, 0xaf, 0x0b, 0xa7, 0x70);
457 #define IID_IMediaControl MP_IID_IMediaControl
458 static DEFINE_GUID(IID_IMediaControl
, 0x56a868b1, 0x0ad4, 0x11ce, 0xb0, 0x3a,
459 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70);
460 #define IID_IAMTVTuner MP_IID_IAMTVTuner
461 static DEFINE_GUID(IID_IAMTVTuner
, 0x211A8766, 0x03AC, 0x11d1, 0x8D, 0x13, 0x00,
462 0xAA, 0x00, 0xBD, 0x83, 0x39);
463 #define IID_IAMCrossbar MP_IID_IAMCrossbar
464 static DEFINE_GUID(IID_IAMCrossbar
, 0xc6e13380, 0x30ac, 0x11d0, 0xa1, 0x8c, 0x00,
465 0xa0, 0xc9, 0x11, 0x89, 0x56);
466 #define IID_IAMStreamConfig MP_IID_IAMStreamConfig
467 static DEFINE_GUID(IID_IAMStreamConfig
, 0xc6e13340, 0x30ac, 0x11d0, 0xa1, 0x8c,
468 0x00, 0xa0, 0xc9, 0x11, 0x89, 0x56);
469 #define IID_IAMAudioInputMixer MP_IID_IAMAudioInputMixer
470 static DEFINE_GUID(IID_IAMAudioInputMixer
, 0x54C39221, 0x8380, 0x11d0, 0xB3, 0xF0,
471 0x00, 0xAA, 0x00, 0x37, 0x61, 0xC5);
472 #define IID_IAMTVAudio MP_IID_IAMTVAudio
473 static DEFINE_GUID(IID_IAMTVAudio
, 0x83EC1C30, 0x23D1, 0x11d1, 0x99, 0xE6, 0x00,
474 0xA0, 0xC9, 0x56, 0x02, 0x66);
475 #define IID_IAMAnalogVideoDecoder MP_IID_IAMAnalogVideoDecoder
476 static DEFINE_GUID(IID_IAMAnalogVideoDecoder
, 0xC6E13350, 0x30AC, 0x11d0, 0xA1,
477 0x8C, 0x00, 0xA0, 0xC9, 0x11, 0x89, 0x56);
478 #define IID_IPropertyBag MP_IID_IPropertyBag
479 static DEFINE_GUID(IID_IPropertyBag
, 0x55272a00, 0x42cb, 0x11ce, 0x81, 0x35, 0x00,
480 0xaa, 0x00, 0x4b, 0xb8, 0x51);
481 #define PIN_CATEGORY_CAPTURE MP_PIN_CATEGORY_CAPTURE
482 static DEFINE_GUID(PIN_CATEGORY_CAPTURE
, 0xfb6c4281, 0x0353, 0x11d1, 0x90, 0x5f,
483 0x00, 0x00, 0xc0, 0xcc, 0x16, 0xba);
484 #define PIN_CATEGORY_VIDEOPORT MP_PIN_CATEGORY_VIDEOPORT
485 static DEFINE_GUID(PIN_CATEGORY_VIDEOPORT
, 0xfb6c4285, 0x0353, 0x11d1, 0x90, 0x5f,
486 0x00, 0x00, 0xc0, 0xcc, 0x16, 0xba);
487 #define PIN_CATEGORY_PREVIEW MP_PIN_CATEGORY_PREVIEW
488 static DEFINE_GUID(PIN_CATEGORY_PREVIEW
, 0xfb6c4282, 0x0353, 0x11d1, 0x90, 0x5f,
489 0x00, 0x00, 0xc0, 0xcc, 0x16, 0xba);
490 #define PIN_CATEGORY_VBI MP_PIN_CATEGORY_VBI
491 static DEFINE_GUID(PIN_CATEGORY_VBI
, 0xfb6c4284, 0x0353, 0x11d1, 0x90, 0x5f,
492 0x00, 0x00, 0xc0, 0xcc, 0x16, 0xba);
493 #define PROPSETID_TUNER MP_PROPSETID_TUNER
494 static DEFINE_GUID(PROPSETID_TUNER
, 0x6a2e0605, 0x28e4, 0x11d0, 0xa1, 0x8c, 0x00,
495 0xa0, 0xc9, 0x11, 0x89, 0x56);
496 #define MEDIATYPE_VBI MP_MEDIATYPE_VBI
497 static DEFINE_GUID(MEDIATYPE_VBI
, 0xf72a76e1, 0xeb0a, 0x11d0, 0xac, 0xe4, 0x00,
498 0x00, 0xc0, 0xcc, 0x16, 0xba);
500 #define INSTANCEDATA_OF_PROPERTY_PTR(x) (((KSPROPERTY*)(x)) + 1)
501 #define INSTANCEDATA_OF_PROPERTY_SIZE(x) (sizeof((x)) - sizeof(KSPROPERTY))
503 #define DEVICE_NAME_MAX_LEN 2000
505 /*---------------------------------------------------------------------------------------
506 * Methods, called only from this file
507 *---------------------------------------------------------------------------------------*/
509 void set_buffer_preference(int nDiv
,WAVEFORMATEX
* pWF
,IPin
* pOutPin
,IPin
* pInPin
){
510 ALLOCATOR_PROPERTIES prop
;
511 IAMBufferNegotiation
* pBN
;
515 prop
.cbBuffer
= pWF
->nAvgBytesPerSec
/nDiv
;
518 prop
.cbBuffer
+= pWF
->nBlockAlign
- 1;
519 prop
.cbBuffer
-= prop
.cbBuffer
% pWF
->nBlockAlign
;
523 hr
=OLE_QUERYINTERFACE(pOutPin
,IID_IAMBufferNegotiation
,pBN
);
525 mp_msg(MSGT_TV
,MSGL_DBG2
,"tvi_dshow: pOutPin->QueryInterface(IID_IAMBufferNegotiation) Error: 0x%x\n",(unsigned int)hr
);
527 hr
=OLE_CALL_ARGS(pBN
,SuggestAllocatorProperties
,&prop
);
529 mp_msg(MSGT_TV
,MSGL_DBG2
,"tvi_dshow:pOutPin->SuggestAllocatorProperties Error:0x%x\n",(unsigned int)hr
);
530 OLE_RELEASE_SAFE(pBN
);
532 hr
=OLE_QUERYINTERFACE(pInPin
,IID_IAMBufferNegotiation
,pBN
);
534 mp_msg(MSGT_TV
,MSGL_DBG2
,"tvi_dshow: pInPin->QueryInterface(IID_IAMBufferNegotiation) Error: 0x%x",(unsigned int)hr
);
536 hr
=OLE_CALL_ARGS(pBN
,SuggestAllocatorProperties
,&prop
);
538 mp_msg(MSGT_TV
,MSGL_DBG2
,"tvi_dshow: pInPit->SuggestAllocatorProperties Error:0x%x\n",(unsigned int)hr
);
539 OLE_RELEASE_SAFE(pBN
);
543 *---------------------------------------------------------------------------------------
545 * CSampleGrabberCD class. Used for receiving samples from DirectShow.
547 *---------------------------------------------------------------------------------------
549 /// CSampleGrabberCD destructor
550 static void CSampleGrabberCB_Destroy(CSampleGrabberCB
* This
)
556 /// CSampleGrabberCD IUnknown interface methods implementation
557 static long STDCALL
CSampleGrabberCB_QueryInterface(ISampleGrabberCB
*
562 CSampleGrabberCB
*me
= (CSampleGrabberCB
*) This
;
565 Debug
printf("CSampleGrabberCB_QueryInterface(%p) called\n", This
);
568 for (r
= me
->interfaces
;
569 i
< sizeof(me
->interfaces
) / sizeof(me
->interfaces
[0]); r
++, i
++)
570 if (!memcmp(r
, riid
, sizeof(*r
))) {
571 OLE_CALL(This
, AddRef
);
575 Debug
printf("Query failed! (GUID: 0x%x)\n", *(unsigned int *) riid
);
576 return E_NOINTERFACE
;
579 static long STDCALL
CSampleGrabberCB_AddRef(ISampleGrabberCB
* This
)
581 CSampleGrabberCB
*me
= (CSampleGrabberCB
*) This
;
582 Debug
printf("CSampleGrabberCB_AddRef(%p) called (ref:%d)\n", This
,
584 return ++(me
->refcount
);
587 static long STDCALL
CSampleGrabberCB_Release(ISampleGrabberCB
* This
)
589 CSampleGrabberCB
*me
= (CSampleGrabberCB
*) This
;
590 Debug
printf("CSampleGrabberCB_Release(%p) called (new ref:%d)\n",
591 This
, me
->refcount
- 1);
592 if (--(me
->refcount
) == 0)
593 CSampleGrabberCB_Destroy(me
);
598 HRESULT STDCALL
CSampleGrabberCB_BufferCB(ISampleGrabberCB
* This
,
600 BYTE
* pBuffer
, long lBufferLen
)
602 CSampleGrabberCB
*this = (CSampleGrabberCB
*) This
;
603 grabber_ringbuffer_t
*rb
= this->pbuf
;
608 if (!rb
->ringbuffer
) {
609 rb
->buffersize
/= lBufferLen
;
610 if (init_ringbuffer(rb
, rb
->buffersize
, lBufferLen
) != S_OK
)
613 mp_msg(MSGT_TV
, MSGL_DBG4
,
614 "tvi_dshow: BufferCB(%p): len=%ld ts=%f\n", This
, lBufferLen
, SampleTime
);
615 EnterCriticalSection(rb
->pMutex
);
616 if (rb
->count
>= rb
->buffersize
) {
617 rb
->head
= (rb
->head
+ 1) % rb
->buffersize
;
621 memcpy(rb
->ringbuffer
[rb
->tail
], pBuffer
,
622 lBufferLen
< rb
->blocksize
? lBufferLen
: rb
->blocksize
);
623 rb
->dpts
[rb
->tail
] = SampleTime
;
624 rb
->tail
= (rb
->tail
+ 1) % rb
->buffersize
;
626 LeaveCriticalSection(rb
->pMutex
);
631 /// wrapper. directshow does the same when BufferCB callback is requested
632 HRESULT STDCALL
CSampleGrabberCB_SampleCB(ISampleGrabberCB
* This
,
634 LPMEDIASAMPLE pSample
)
638 long long tStart
,tEnd
;
640 grabber_ringbuffer_t
*rb
= ((CSampleGrabberCB
*)This
)->pbuf
;
642 len
=OLE_CALL(pSample
,GetSize
);
644 hr
=OLE_CALL_ARGS(pSample
,GetTime
,&tStart
,&tEnd
);
648 mp_msg(MSGT_TV
, MSGL_DBG4
,"tvi_dshow: SampleCB(%p): %d/%d %f\n", This
,rb
->count
,rb
->buffersize
,1e-7*tStart
);
649 hr
=OLE_CALL_ARGS(pSample
,GetPointer
,(void*)&buf
);
653 hr
=CSampleGrabberCB_BufferCB(This
,1e-7*tStart
,buf
,len
);
658 /// main grabbing routine
659 static CSampleGrabberCB
*CSampleGrabberCB_Create(grabber_ringbuffer_t
*
662 CSampleGrabberCB
*This
= malloc(sizeof(CSampleGrabberCB
));
666 This
->lpVtbl
= malloc(sizeof(ISampleGrabberVtbl
));
668 CSampleGrabberCB_Destroy(This
);
672 This
->lpVtbl
->QueryInterface
= CSampleGrabberCB_QueryInterface
;
673 This
->lpVtbl
->AddRef
= CSampleGrabberCB_AddRef
;
674 This
->lpVtbl
->Release
= CSampleGrabberCB_Release
;
675 This
->lpVtbl
->SampleCB
= CSampleGrabberCB_SampleCB
;
676 This
->lpVtbl
->BufferCB
= CSampleGrabberCB_BufferCB
;
678 This
->interfaces
[0] = IID_IUnknown
;
679 This
->interfaces
[1] = IID_ISampleGrabberCB
;
687 *---------------------------------------------------------------------------------------
689 * ROT related methods (register, unregister)
691 *---------------------------------------------------------------------------------------
694 Registering graph in ROT. User will be able to connect to graph from GraphEdit.
696 static HRESULT
AddToRot(IUnknown
* pUnkGraph
, DWORD
* pdwRegister
)
699 IRunningObjectTable
*pROT
;
703 if (FAILED(GetRunningObjectTable(0, &pROT
))) {
706 wsprintfW(wsz
, L
"FilterGraph %08x pid %08x", (DWORD_PTR
) pUnkGraph
,
707 GetCurrentProcessId());
708 hr
= CreateItemMoniker(L
"!", wsz
, &pMoniker
);
710 hr
= OLE_CALL_ARGS(pROT
, Register
, ROTFLAGS_REGISTRATIONKEEPSALIVE
,
711 pUnkGraph
, pMoniker
, pdwRegister
);
712 OLE_RELEASE_SAFE(pMoniker
);
714 OLE_RELEASE_SAFE(pROT
);
718 /// Unregistering graph in ROT
719 static void RemoveFromRot(DWORD dwRegister
)
721 IRunningObjectTable
*pROT
;
722 if (SUCCEEDED(GetRunningObjectTable(0, &pROT
))) {
723 OLE_CALL_ARGS(pROT
, Revoke
, dwRegister
);
724 OLE_RELEASE_SAFE(pROT
);
729 *---------------------------------------------------------------------------------------
731 * ringbuffer related methods (init, destroy)
733 *---------------------------------------------------------------------------------------
736 * \brief ringbuffer destroying routine
738 * \param rb pointer to empty (just allocated) ringbuffer structure
740 * \note routine does not frees memory, allocated for grabber_rinbuffer_s structure
742 static void destroy_ringbuffer(grabber_ringbuffer_t
* rb
)
749 if (rb
->ringbuffer
) {
750 for (i
= 0; i
< rb
->buffersize
; i
++)
751 if (rb
->ringbuffer
[i
])
752 free(rb
->ringbuffer
[i
]);
753 free(rb
->ringbuffer
);
754 rb
->ringbuffer
= NULL
;
761 DeleteCriticalSection(rb
->pMutex
);
774 * \brief ringbuffer initialization
776 * \param rb pointer to empty (just allocated) ringbuffer structure
777 * \param buffersize size of buffer in blocks
778 * \param blocksize size of buffer's block
780 * \return S_OK if success
781 * \return E_OUTOFMEMORY not enough memory
783 * \note routine does not allocates memory for grabber_rinbuffer_s structure
785 static HRESULT
init_ringbuffer(grabber_ringbuffer_t
* rb
, int buffersize
,
791 return E_OUTOFMEMORY
;
793 rb
->buffersize
= buffersize
< 2 ? 2 : buffersize
;
794 rb
->blocksize
= blocksize
;
796 mp_msg(MSGT_TV
, MSGL_DBG2
, "tvi_dshow: Capture buffer: %d blocks of %d bytes.\n",
797 rb
->buffersize
, rb
->blocksize
);
799 rb
->ringbuffer
= malloc(rb
->buffersize
* sizeof(char *));
802 memset(rb
->ringbuffer
, 0, rb
->buffersize
* sizeof(char *));
804 for (i
= 0; i
< rb
->buffersize
; i
++) {
805 rb
->ringbuffer
[i
] = malloc(rb
->blocksize
* sizeof(char));
806 if (!rb
->ringbuffer
[i
]) {
807 destroy_ringbuffer(rb
);
808 return E_OUTOFMEMORY
;
811 rb
->dpts
= malloc(rb
->buffersize
* sizeof(double));
813 destroy_ringbuffer(rb
);
814 return E_OUTOFMEMORY
;
820 rb
->pMutex
= malloc(sizeof(CRITICAL_SECTION
));
822 destroy_ringbuffer(rb
);
823 return E_OUTOFMEMORY
;
825 InitializeCriticalSection(rb
->pMutex
);
830 *---------------------------------------------------------------------------------------
832 * Tuner related methods (frequency, capabilities, etc
834 *---------------------------------------------------------------------------------------
837 * \brief returns string with name for givend PsysCon_* constant
839 * \param lPhysicalType constant from PhysicalConnectorType enumeration
841 * \return pointer to string with apropriate name
844 * Caller should not free returned pointer
846 static char *physcon2str(const long lPhysicalType
)
849 for(i
=0; tv_physcon_types
[i
].name
; i
++)
850 if(tv_physcon_types
[i
].type
==lPhysicalType
)
851 return tv_physcon_types
[i
].name
;
856 * \brief converts MPlayer's chanlist to system country code.
858 * \param chanlist MPlayer's chanlist name
860 * \return system country code
863 * After call to IAMTVTuner::put_CountryCode with returned value tuner switches to frequency table used in specified
864 * country (which is usually larger then MPlayer's one, so workaround will work fine).
867 * Resolve trouble with cable channels (DirectShow's tuners must be switched between broadcast and cable channels modes.
869 static int chanlist2country(char *chanlist
)
872 for(i
=0; tv_chanlist2country
[i
].chanlist_name
; i
++)
873 if (!strcmp(chanlist
, tv_chanlist2country
[i
].chanlist_name
))
875 return tv_chanlist2country
[i
].country_code
;
879 * \brief loads specified resource from module and return pointer to it
881 * \param hDLL valid module desriptor
882 * \param index index of resource. resource with name "#<index>" will be loaded
884 * \return pointer to loader resource or NULL if error occured
886 static void *GetRC(HMODULE hDLL
, int index
)
893 snprintf(szRCDATA
, 10, "#%d", (int)RT_RCDATA
);
894 snprintf(szName
, 10, "#%d", index
);
896 hRes
= FindResource(hDLL
, szName
, szRCDATA
);
900 hTable
= LoadResource(hDLL
, hRes
);
904 return LockResource(hTable
);
908 * \brief loads frequency table for given country from kstvtune.ax
910 * \param[in] nCountry - country code
911 * \param[in] nInputType (TunerInputCable or TunerInputAntenna)
912 * \param[out] pplFreqTable - address of variable that receives pointer to array, containing frequencies
913 * \param[out] pnLen length of array
914 * \param[out] pnFirst - channel number of first entry in array (nChannelMax)
916 * \return S_OK if success
917 * \return E_POINTER pplFreqTable==NULL || plFirst==NULL || pnLen==NULL
918 * \return E_FAIL error occured during load
921 * - array must be freed by caller
922 * - MSDN says that it is not neccessery to unlock or free resource. It will be done after unloading DLL
924 static HRESULT
load_freq_table(int nCountry
, int nInputType
,
925 long **pplFreqTable
, int *pnLen
,
930 TRCCountryList
*pCountryList
;
933 mp_msg(MSGT_TV
, MSGL_DBG4
, "tvi_dshow: load_freq_table called %d (%s)\n",nCountry
,nInputType
== TunerInputAntenna
? "broadcast" : "cable");
934 /* ASSERT(sizeof(TRCCountryList)==10); // need properly aligned structure */
936 if (!pplFreqTable
|| !pnFirst
|| !pnLen
)
941 hDLL
= LoadLibrary("kstvtune.ax");
945 pCountryList
= GetRC(hDLL
, 9999);
950 for (i
= 0; pCountryList
[i
].CountryCode
!= 0; i
++)
951 if (pCountryList
[i
].CountryCode
== nCountry
)
953 if (pCountryList
[i
].CountryCode
== 0) {
957 if (nInputType
== TunerInputCable
)
958 index
= pCountryList
[i
].CableFreqTable
;
960 index
= pCountryList
[i
].BroadcastFreqTable
;
962 plFreqTable
= GetRC(hDLL
, index
); //First element is number of first channel, second - number of last channel
967 *pnFirst
= plFreqTable
[0];
968 *pnLen
= (int) (plFreqTable
[1] - plFreqTable
[0] + 1);
969 *pplFreqTable
= malloc((*pnLen
) * sizeof(long));
970 if (!*pplFreqTable
) {
974 for (i
= 0; i
< *pnLen
; i
++) {
975 (*pplFreqTable
)[i
] = plFreqTable
[i
+ 2];
976 mp_msg(MSGT_TV
, MSGL_DBG4
, "tvi_dshow: load_freq_table #%d => (%ld)\n",i
+*pnFirst
,(*pplFreqTable
)[i
]);
983 * \brief tunes to given frequency through IKsPropertySet call
985 * \param pTVTuner IAMTVTuner interface of capture device
986 * \param lFreq frequency to tune (in Hz)
988 * \return S_OK success
989 * \return apropriate error code otherwise
992 * Due to either bug in driver or error in following code calll to IKsProperty::Set
993 * in this methods always fail with error 0x8007007a.
995 * \todo test code on other machines and an error
997 static HRESULT
set_frequency_direct(IAMTVTuner
* pTVTuner
, long lFreq
)
1000 DWORD dwSupported
= 0;
1002 KSPROPERTY_TUNER_MODE_CAPS_S mode_caps
;
1003 KSPROPERTY_TUNER_FREQUENCY_S frequency
;
1004 IKsPropertySet
*pKSProp
;
1006 mp_msg(MSGT_TV
, MSGL_DBG4
, "tvi_dshow: set_frequency_direct called\n");
1008 memset(&mode_caps
, 0, sizeof(mode_caps
));
1009 memset(&frequency
, 0, sizeof(frequency
));
1011 hr
= OLE_QUERYINTERFACE(pTVTuner
, IID_IKsPropertySet
, pKSProp
);
1013 return hr
; //no IKsPropertySet interface
1015 mode_caps
.Mode
= AMTUNER_MODE_TV
;
1016 hr
= OLE_CALL_ARGS(pKSProp
, QuerySupported
, &PROPSETID_TUNER
,
1017 KSPROPERTY_TUNER_MODE_CAPS
, &dwSupported
);
1019 OLE_RELEASE_SAFE(pKSProp
);
1023 if (!dwSupported
& KSPROPERTY_SUPPORT_GET
) {
1024 OLE_RELEASE_SAFE(pKSProp
);
1025 return E_FAIL
; //PROPSETID_TINER not supported
1028 hr
= OLE_CALL_ARGS(pKSProp
, Get
, &PROPSETID_TUNER
,
1029 KSPROPERTY_TUNER_MODE_CAPS
,
1030 INSTANCEDATA_OF_PROPERTY_PTR(&mode_caps
),
1031 INSTANCEDATA_OF_PROPERTY_SIZE(mode_caps
),
1032 &mode_caps
, sizeof(mode_caps
), &cbBytes
);
1034 frequency
.Frequency
= lFreq
;
1036 if (mode_caps
.Strategy
== KS_TUNER_STRATEGY_DRIVER_TUNES
)
1037 frequency
.TuningFlags
= KS_TUNER_TUNING_FINE
;
1039 frequency
.TuningFlags
= KS_TUNER_TUNING_EXACT
;
1041 if (lFreq
< mode_caps
.MinFrequency
|| lFreq
> mode_caps
.MaxFrequency
) {
1042 OLE_RELEASE_SAFE(pKSProp
);
1046 hr
= OLE_CALL_ARGS(pKSProp
, Set
, &PROPSETID_TUNER
,
1047 KSPROPERTY_TUNER_FREQUENCY
,
1048 INSTANCEDATA_OF_PROPERTY_PTR(&frequency
),
1049 INSTANCEDATA_OF_PROPERTY_SIZE(frequency
),
1050 &frequency
, sizeof(frequency
));
1052 OLE_RELEASE_SAFE(pKSProp
);
1056 OLE_RELEASE_SAFE(pKSProp
);
1062 * \brief find channel with nearest frequency and set it
1064 * \param priv driver's private data
1065 * \param lFreq frequency in Hz
1067 * \return S_OK if success
1068 * \return E_FAIL if error occured
1070 static HRESULT
set_nearest_freq(priv_t
* priv
, long lFreq
)
1076 TunerInputType tunerInput
;
1079 mp_msg(MSGT_TV
, MSGL_DBG4
, "tvi_dshow: set_nearest_freq called: %ld\n", lFreq
);
1080 if(priv
->freq_table_len
== -1 && !priv
->freq_table
) {
1082 hr
= OLE_CALL_ARGS(priv
->pTVTuner
, get_ConnectInput
, &lInput
);
1083 if(FAILED(hr
)){ //Falling back to 0
1087 hr
= OLE_CALL_ARGS(priv
->pTVTuner
, get_InputType
, lInput
, &tunerInput
);
1089 if (load_freq_table(chanlist2country(priv
->tv_param
->chanlist
), tunerInput
, &(priv
->freq_table
), &(priv
->freq_table_len
), &(priv
->first_channel
)) != S_OK
) {//FIXME
1090 priv
->freq_table_len
=0;
1091 priv
->freq_table
=NULL
;
1092 mp_msg(MSGT_TV
, MSGL_ERR
, MSGTR_TVI_DS_UnableExtractFreqTable
);
1095 mp_msg(MSGT_TV
, MSGL_V
, MSGTR_TVI_DS_FreqTableLoaded
, tunerInput
== TunerInputAntenna
? "broadcast" : "cable",
1096 chanlist2country(priv
->tv_param
->chanlist
), priv
->freq_table_len
);
1099 if (priv
->freq_table_len
<= 0)
1102 //FIXME: rewrite search algo
1104 for (i
= 0; i
< priv
->freq_table_len
; i
++) {
1105 if (nChannel
== -1 || labs(lFreq
- priv
->freq_table
[i
]) < lFreqDiff
) {
1106 nChannel
= priv
->first_channel
+ i
;
1107 lFreqDiff
= labs(lFreq
- priv
->freq_table
[i
]);
1109 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
);
1111 if (nChannel
== -1) {
1112 mp_msg(MSGT_TV
,MSGL_ERR
, MSGTR_TVI_DS_UnableFindNearestChannel
);
1115 mp_msg(MSGT_TV
, MSGL_V
, "tvi_dshow: set_nearest_freq #%d (%ld)\n",nChannel
,priv
->freq_table
[nChannel
- priv
->first_channel
]);
1116 hr
= OLE_CALL_ARGS(priv
->pTVTuner
, put_Channel
, nChannel
,
1117 AMTUNER_SUBCHAN_DEFAULT
, AMTUNER_SUBCHAN_DEFAULT
);
1119 mp_msg(MSGT_TV
,MSGL_ERR
,MSGTR_TVI_DS_UnableToSetChannel
, (unsigned int)hr
);
1126 * \brief setting frequency. decides whether use direct call/workaround
1128 * \param priv driver's private data
1129 * \param lFreq frequency in Hz
1131 * \return TVI_CONTROL_TRUE if success
1132 * \return TVI_CONTROL_FALSE if error occured
1134 * \todo check for freq boundary
1136 static int set_frequency(priv_t
* priv
, long lFreq
)
1140 mp_msg(MSGT_TV
, MSGL_DBG4
, "tvi_dshow: set_frequency called: %ld\n", lFreq
);
1141 if (!priv
->pTVTuner
)
1142 return TVI_CONTROL_FALSE
;
1143 if (priv
->direct_setfreq_call
) { //using direct call to set frequency
1144 hr
= set_frequency_direct(priv
->pTVTuner
, lFreq
);
1146 mp_msg(MSGT_TV
, MSGL_V
, MSGTR_TVI_DS_DirectSetFreqFailed
);
1147 priv
->direct_setfreq_call
= 0;
1150 if (!priv
->direct_setfreq_call
) {
1151 hr
= set_nearest_freq(priv
, lFreq
);
1154 return TVI_CONTROL_FALSE
;
1156 priv
->pGrabber
->ClearBuffer(priv
->pGrabber
);
1158 return TVI_CONTROL_TRUE
;
1162 * \brief return current frequency from tuner (in Hz)
1164 * \param pTVTuner IAMTVTuner interface of tuner
1165 * \param plFreq address of variable that receives current frequency
1167 * \return S_OK success
1168 * \return E_POINTER pTVTuner==NULL || plFreq==NULL
1169 * \return apropriate error code otherwise
1171 static HRESULT
get_frequency_direct(IAMTVTuner
* pTVTuner
, long *plFreq
)
1174 KSPROPERTY_TUNER_STATUS_S TunerStatus
;
1176 IKsPropertySet
*pKSProp
;
1177 mp_msg(MSGT_TV
, MSGL_DBG4
, "tvi_dshow: get_frequency_direct called\n");
1182 hr
= OLE_QUERYINTERFACE(pTVTuner
, IID_IKsPropertySet
, pKSProp
);
1184 mp_msg(MSGT_TV
, MSGL_DBG2
, "tvi_dshow: Get freq QueryInterface failed\n");
1188 hr
= OLE_CALL_ARGS(pKSProp
, Get
, &PROPSETID_TUNER
,
1189 KSPROPERTY_TUNER_STATUS
,
1190 INSTANCEDATA_OF_PROPERTY_PTR(&TunerStatus
),
1191 INSTANCEDATA_OF_PROPERTY_SIZE(TunerStatus
),
1192 &TunerStatus
, sizeof(TunerStatus
), &cbBytes
);
1194 mp_msg(MSGT_TV
, MSGL_DBG2
, "tvi_dshow: Get freq Get failure\n");
1197 *plFreq
= TunerStatus
.CurrentFrequency
;
1202 * \brief gets current frequency
1204 * \param priv driver's private data structure
1205 * \param plFreq - pointer to long int to store frequency to (in Hz)
1207 * \return TVI_CONTROL_TRUE if success, TVI_CONTROL_FALSE otherwise
1209 static int get_frequency(priv_t
* priv
, long *plFreq
)
1213 mp_msg(MSGT_TV
, MSGL_DBG4
, "tvi_dshow: get_frequency called\n");
1215 if (!plFreq
|| !priv
->pTVTuner
)
1216 return TVI_CONTROL_FALSE
;
1218 if (priv
->direct_getfreq_call
) { //using direct call to get frequency
1219 hr
= get_frequency_direct(priv
->pTVTuner
, plFreq
);
1221 mp_msg(MSGT_TV
, MSGL_INFO
, MSGTR_TVI_DS_DirectGetFreqFailed
);
1222 priv
->direct_getfreq_call
= 0;
1225 if (!priv
->direct_getfreq_call
) {
1226 hr
=OLE_CALL_ARGS(priv
->pTVTuner
, get_VideoFrequency
, plFreq
);
1228 return TVI_CONTROL_FALSE
;
1231 return TVI_CONTROL_TRUE
;
1235 * \brief get tuner capabilities
1237 * \param priv driver's private data
1239 static void get_capabilities(priv_t
* priv
)
1241 long lAvailableFormats
;
1244 long lInputPins
, lOutputPins
, lRelated
, lPhysicalType
;
1248 PIN_DIRECTION ThisPinDir
;
1250 IAMAudioInputMixer
*pIAMixer
;
1252 mp_msg(MSGT_TV
, MSGL_DBG4
, "tvi_dshow: get_capabilities called\n");
1253 if (priv
->pTVTuner
) {
1255 mp_msg(MSGT_TV
, MSGL_V
, MSGTR_TVI_DS_SupportedNorms
);
1256 hr
= OLE_CALL_ARGS(priv
->pTVTuner
, get_AvailableTVFormats
,
1257 &lAvailableFormats
);
1259 tv_available_norms_count
= 0;
1261 for (i
= 0; i
< TV_NORMS_COUNT
; i
++) {
1262 if (lAvailableFormats
& tv_norms
[i
].index
) {
1263 tv_available_norms
[tv_available_norms_count
] = i
;
1264 mp_msg(MSGT_TV
, MSGL_V
, " %d=%s;",
1265 tv_available_norms_count
+ 1, tv_norms
[i
].name
);
1266 tv_available_norms_count
++;
1270 mp_msg(MSGT_TV
, MSGL_INFO
, "\n");
1272 if (priv
->pCrossbar
) {
1273 OLE_CALL_ARGS(priv
->pCrossbar
, get_PinCounts
, &lOutputPins
,
1276 tv_available_inputs
= malloc(sizeof(long) * lInputPins
);
1277 tv_available_inputs_count
= 0;
1279 mp_msg(MSGT_TV
, MSGL_V
, MSGTR_TVI_DS_AvailableVideoInputs
);
1280 for (i
= 0; i
< lInputPins
; i
++) {
1281 OLE_CALL_ARGS(priv
->pCrossbar
, get_CrossbarPinInfo
, 1, i
,
1282 &lRelated
, &lPhysicalType
);
1284 if (lPhysicalType
< 0x1000) {
1285 tv_available_inputs
[tv_available_inputs_count
++] = i
;
1286 mp_msg(MSGT_TV
, MSGL_V
, " %d=%s;",
1287 tv_available_inputs_count
- 1,
1288 physcon2str(lPhysicalType
));
1291 mp_msg(MSGT_TV
, MSGL_INFO
, "\n");
1293 set_crossbar_input(priv
, 0);
1296 if (priv
->adev_index
!= -1) {
1297 hr
= OLE_CALL_ARGS(priv
->chains
[1]->pCaptureFilter
, EnumPins
, &pEnum
);
1300 mp_msg(MSGT_TV
, MSGL_V
, MSGTR_TVI_DS_AvailableAudioInputs
);
1302 while (OLE_CALL_ARGS(pEnum
, Next
, 1, &pPin
, NULL
) == S_OK
) {
1303 memset(&pi
, 0, sizeof(pi
));
1304 memset(tmp
, 0, 200);
1305 OLE_CALL_ARGS(pPin
, QueryDirection
, &ThisPinDir
);
1306 if (ThisPinDir
== PINDIR_INPUT
) {
1307 OLE_CALL_ARGS(pPin
, QueryPinInfo
, &pi
);
1308 wtoa(pi
.achName
, tmp
, 200);
1309 OLE_RELEASE_SAFE(pi
.pFilter
);
1310 mp_msg(MSGT_TV
, MSGL_V
, " %d=%s", i
, tmp
);
1311 mp_msg(MSGT_TV
, MSGL_DBG3
, " (%p)", pPin
);
1312 hr
= OLE_QUERYINTERFACE(pPin
, IID_IAMAudioInputMixer
,pIAMixer
);
1313 if (SUCCEEDED(hr
)) {
1314 if (i
== priv
->tv_param
->audio_id
) {
1315 OLE_CALL_ARGS(pIAMixer
, put_Enable
, TRUE
);
1316 if(priv
->tv_param
->volume
>0)
1317 OLE_CALL_ARGS(pIAMixer
, put_MixLevel
, 0.01 * priv
->tv_param
->volume
);
1320 OLE_CALL_ARGS(pIAMixer
, put_MixLevel
, 1.0);
1322 mp_msg(MSGT_TV
, MSGL_V
, MSGTR_TVI_DS_InputSelected
);
1324 OLE_CALL_ARGS(pIAMixer
, put_Enable
, FALSE
);
1326 OLE_CALL_ARGS(pIAMixer
, put_MixLevel
, 0.0);
1329 OLE_RELEASE_SAFE(pIAMixer
);
1331 mp_msg(MSGT_TV
, MSGL_V
, ";");
1332 OLE_RELEASE_SAFE(pPin
);
1336 mp_msg(MSGT_TV
, MSGL_INFO
, "\n");
1337 OLE_RELEASE_SAFE(pEnum
);
1342 *---------------------------------------------------------------------------------------
1344 * Filter related methods
1346 *---------------------------------------------------------------------------------------
1349 * \brief building in graph audio/video capture chain
1351 * \param priv driver's private data
1352 * \param pCaptureFilter pointer to capture device's IBaseFilter interface
1353 * \param pbuf ringbuffer data structure
1354 * \param pmt media type for chain (AM_MEDIA_TYPE)
1356 * \note routine does not frees memory, allocated for grabber_rinbuffer_s structure
1358 static HRESULT
build_sub_graph(priv_t
* priv
, chain_t
* chain
, const GUID
* ppin_category
)
1361 int nFormatProbed
= 0;
1366 IBaseFilter
*pNR
= NULL
;
1370 //No supported formats
1371 if(!chain
->arpmt
[0])
1375 hr
= OLE_CALL_ARGS(priv
->pBuilder
, FindPin
,
1376 (IUnknown
*) chain
->pCaptureFilter
,
1377 PINDIR_OUTPUT
, ppin_category
,
1378 chain
->majortype
, FALSE
, 0, &chain
->pCapturePin
);
1380 mp_msg(MSGT_TV
,MSGL_DBG2
, "tvi_dshow: FindPin(pCapturePin) call failed. Error:0x%x\n", (unsigned int)hr
);
1383 /* Addinf SampleGrabber filter for video stream */
1384 hr
= CoCreateInstance((GUID
*) & CLSID_SampleGrabber
, NULL
,CLSCTX_INPROC_SERVER
, &IID_IBaseFilter
,(void *) &chain
->pSGF
);
1386 mp_msg(MSGT_TV
,MSGL_DBG2
, "tvi_dshow: CoCreateInstance(SampleGrabber) call failed. Error:0x%x\n", (unsigned int)hr
);
1389 hr
= OLE_CALL_ARGS(priv
->pGraph
, AddFilter
, chain
->pSGF
, L
"Sample Grabber");
1391 mp_msg(MSGT_TV
,MSGL_DBG2
,"tvi_dshow: AddFilter(SampleGrabber) call failed. Error:0x%x\n", (unsigned int)hr
);
1394 hr
= OLE_CALL_ARGS(priv
->pBuilder
, FindPin
, (IUnknown
*) chain
->pSGF
,PINDIR_INPUT
, NULL
, NULL
, FALSE
, 0, &chain
->pSGIn
);
1396 mp_msg(MSGT_TV
,MSGL_DBG2
,"tvi_dshow: FindPin(pSGIn) call failed. Error:0x%x\n", (unsigned int)hr
);
1399 hr
= OLE_CALL_ARGS(priv
->pBuilder
, FindPin
, (IUnknown
*) chain
->pSGF
,PINDIR_OUTPUT
, NULL
, NULL
, FALSE
, 0, &pSGOut
);
1401 mp_msg(MSGT_TV
,MSGL_DBG2
,"tvi_dshow: FindPin(pSGOut) call failed. Error:0x%x\n", (unsigned int)hr
);
1405 /* creating ringbuffer for video samples */
1406 chain
->pCSGCB
= CSampleGrabberCB_Create(chain
->rbuf
);
1408 mp_msg(MSGT_TV
,MSGL_DBG2
, "tvi_dshow: CSampleGrabberCB_Create(pbuf) call failed. Error:0x%x\n", (unsigned int)E_OUTOFMEMORY
);
1412 /* initializing SampleGrabber filter */
1413 hr
= OLE_QUERYINTERFACE(chain
->pSGF
, IID_ISampleGrabber
, chain
->pSG
);
1415 mp_msg(MSGT_TV
,MSGL_DBG2
,"tvi_dshow: QueryInterface(IID_ISampleGrabber) call failed. Error:0x%x\n", (unsigned int)hr
);
1418 // hr = OLE_CALL_ARGS(pSG, SetCallback, (ISampleGrabberCB *) pCSGCB, 1); //we want to receive copy of sample's data
1419 hr
= OLE_CALL_ARGS(chain
->pSG
, SetCallback
, (ISampleGrabberCB
*) chain
->pCSGCB
, 0); //we want to receive sample
1422 mp_msg(MSGT_TV
,MSGL_DBG2
,"tvi_dshow: SetCallback(pSG) call failed. Error:0x%x\n", (unsigned int)hr
);
1425 hr
= OLE_CALL_ARGS(chain
->pSG
, SetOneShot
, FALSE
); //... for all frames
1427 mp_msg(MSGT_TV
,MSGL_DBG2
,"tvi_dshow: SetOneShot(pSG) call failed. Error:0x%x\n", (unsigned int)hr
);
1430 hr
= OLE_CALL_ARGS(chain
->pSG
, SetBufferSamples
, FALSE
); //... do not buffer samples in sample grabber
1432 mp_msg(MSGT_TV
,MSGL_DBG2
,"tvi_dshow: SetBufferSamples(pSG) call failed. Error:0x%x\n", (unsigned int)hr
);
1436 if(priv
->tv_param
->normalize_audio_chunks
&& chain
->type
==audio
){
1437 set_buffer_preference(20,(WAVEFORMATEX
*)(chain
->arpmt
[nFormatProbed
]->pbFormat
),chain
->pCapturePin
,chain
->pSGIn
);
1440 for(nFormatProbed
=0; chain
->arpmt
[nFormatProbed
]; nFormatProbed
++)
1442 DisplayMediaType("Probing format", chain
->arpmt
[nFormatProbed
]);
1443 hr
= OLE_CALL_ARGS(chain
->pSG
, SetMediaType
, chain
->arpmt
[nFormatProbed
]); //set desired mediatype
1445 mp_msg(MSGT_TV
,MSGL_DBG2
,"tvi_dshow: SetMediaType(pSG) call failed. Error:0x%x\n", (unsigned int)hr
);
1448 /* connecting filters together: VideoCapture --> SampleGrabber */
1449 hr
= OLE_CALL_ARGS(priv
->pGraph
, Connect
, chain
->pCapturePin
, chain
->pSGIn
);
1451 mp_msg(MSGT_TV
,MSGL_DBG2
,"tvi_dshow: Unable to create pCapturePin<->pSGIn connection. Error:0x%x\n", (unsigned int)hr
);
1457 if(!chain
->arpmt
[nFormatProbed
])
1459 mp_msg(MSGT_TV
, MSGL_WARN
, "tvi_dshow: Unable to negotiate media format\n");
1464 hr
= OLE_CALL_ARGS(chain
->pCapturePin
, ConnectionMediaType
, chain
->pmt
);
1467 mp_msg(MSGT_TV
, MSGL_WARN
, MSGTR_TVI_DS_GetActualMediatypeFailed
, (unsigned int)hr
);
1470 if(priv
->tv_param
->hidden_video_renderer
){
1471 IEnumFilters
* pEnum
;
1472 IBaseFilter
* pFilter
;
1474 hr
=OLE_CALL_ARGS(priv
->pBuilder
,RenderStream
,NULL
,NULL
,(IUnknown
*)chain
->pCapturePin
,NULL
,NULL
);
1476 OLE_CALL_ARGS(priv
->pGraph
, EnumFilters
, &pEnum
);
1477 while (OLE_CALL_ARGS(pEnum
, Next
, 1, &pFilter
, NULL
) == S_OK
) {
1478 LPVIDEOWINDOW pVideoWindow
;
1479 hr
= OLE_QUERYINTERFACE(pFilter
, IID_IVideoWindow
, pVideoWindow
);
1482 OLE_CALL_ARGS(pVideoWindow
,put_Visible
,/* OAFALSE*/ 0);
1483 OLE_CALL_ARGS(pVideoWindow
,put_AutoShow
,/* OAFALSE*/ 0);
1484 OLE_RELEASE_SAFE(pVideoWindow
);
1486 OLE_RELEASE_SAFE(pFilter
);
1488 OLE_RELEASE_SAFE(pEnum
);
1493 Code below is disabled, because terminating chain with NullRenderer leads to jerky video.
1494 Perhaps, this happens because NullRenderer filter discards each received
1495 frame while discarded frames causes live source filter to dramatically reduce frame rate.
1497 /* adding sink for video stream */
1498 hr
= CoCreateInstance((GUID
*) & CLSID_NullRenderer
, NULL
,CLSCTX_INPROC_SERVER
, &IID_IBaseFilter
,(void *) &pNR
);
1500 mp_msg(MSGT_TV
,MSGL_DBG2
,"tvi_dshow: CoCreateInstance(NullRenderer) call failed. Error:0x%x\n", (unsigned int)hr
);
1503 hr
= OLE_CALL_ARGS(priv
->pGraph
, AddFilter
, pNR
, L
"Null Renderer");
1505 mp_msg(MSGT_TV
,MSGL_DBG2
,"tvi_dshow: AddFilter(NullRenderer) call failed. Error:0x%x\n", (unsigned int)hr
);
1508 hr
= OLE_CALL_ARGS(priv
->pBuilder
, FindPin
, (IUnknown
*) pNR
,PINDIR_INPUT
, NULL
, NULL
, FALSE
, 0, &pNRIn
);
1510 mp_msg(MSGT_TV
,MSGL_DBG2
,"tvi_dshow: FindPin(pNRIn) call failed. Error:0x%x\n", (unsigned int)hr
);
1514 Prevent ending VBI chain with NullRenderer filter, because this causes VBI pin disconnection
1516 if(memcmp(&(arpmt
[nFormatProbed
]->majortype
),&MEDIATYPE_VBI
,16)){
1517 /* connecting filters together: SampleGrabber --> NullRenderer */
1518 hr
= OLE_CALL_ARGS(priv
->pGraph
, Connect
, pSGOut
, pNRIn
);
1520 mp_msg(MSGT_TV
,MSGL_DBG2
,"tvi_dshow: Unable to create pSGOut<->pNRIn connection. Error:0x%x\n", (unsigned int)hr
);
1530 OLE_RELEASE_SAFE(pSGOut
);
1531 OLE_RELEASE_SAFE(pNR
);
1532 OLE_RELEASE_SAFE(pNRIn
);
1538 * \brief configures crossbar for grabbing video stream from given input
1540 * \param priv driver's private data
1541 * \param input index of available video input to get data from
1543 * \return TVI_CONTROL_TRUE success
1544 * \return TVI_CONTROL_FALSE error
1546 static int set_crossbar_input(priv_t
* priv
, int input
)
1549 int i
, nVideoDecoder
, nAudioDecoder
;
1550 long lInput
, lInputRelated
, lRelated
, lPhysicalType
, lOutputPins
,
1553 mp_msg(MSGT_TV
, MSGL_DBG4
, "tvi_dshow: Configuring crossbar\n");
1554 if (!priv
->pCrossbar
|| input
< 0
1555 || input
>= tv_available_inputs_count
)
1556 return TVI_CONTROL_FALSE
;
1558 OLE_CALL_ARGS(priv
->pCrossbar
, get_PinCounts
, &lOutputPins
, &lInputPins
);
1560 lInput
= tv_available_inputs
[input
];
1562 if (lInput
< 0 || lInput
>= lInputPins
)
1563 return TVI_CONTROL_FALSE
;
1565 OLE_CALL_ARGS(priv
->pCrossbar
, get_CrossbarPinInfo
, 1 /* input */ , lInput
,
1566 &lInputRelated
, &lPhysicalType
);
1568 nVideoDecoder
= nAudioDecoder
= -1;
1569 for (i
= 0; i
< lOutputPins
; i
++) {
1570 OLE_CALL_ARGS(priv
->pCrossbar
, get_CrossbarPinInfo
, 0 /*output */ , i
,
1571 &lRelated
, &lPhysicalType
);
1572 if (lPhysicalType
== PhysConn_Video_VideoDecoder
)
1574 if (lPhysicalType
== PhysConn_Audio_AudioDecoder
)
1577 if (nVideoDecoder
>= 0) {
1578 //connecting given input with video decoder
1579 hr
= OLE_CALL_ARGS(priv
->pCrossbar
, Route
, nVideoDecoder
, lInput
);
1581 mp_msg(MSGT_TV
,MSGL_ERR
,MSGTR_TVI_DS_UnableConnectInputVideoDecoder
, (unsigned int)hr
);
1582 return TVI_CONTROL_FALSE
;
1585 if (nAudioDecoder
>= 0 && lInputRelated
>= 0) {
1586 hr
= OLE_CALL_ARGS(priv
->pCrossbar
, Route
, nAudioDecoder
,
1589 mp_msg(MSGT_TV
,MSGL_ERR
,MSGTR_TVI_DS_UnableConnectInputAudioDecoder
, (unsigned int)hr
);
1590 return TVI_CONTROL_FALSE
;
1593 return TVI_CONTROL_TRUE
;
1597 * \brief adjusts video control (hue,saturation,contrast,brightess)
1599 * \param priv driver's private data
1600 * \param control which control to adjust
1601 * \param value new value for control (0-100)
1603 * \return TVI_CONTROL_TRUE success
1604 * \return TVI_CONTROL_FALSE error
1606 static int set_control(priv_t
* priv
, int control
, int value
)
1608 long lMin
, lMax
, lStepping
, lDefault
, lFlags
, lValue
;
1611 mp_msg(MSGT_TV
, MSGL_DBG4
, "tvi_dshow: set_control called\n");
1612 if (value
< -100 || value
> 100 || !priv
->pVideoProcAmp
)
1613 return TVI_CONTROL_FALSE
;
1615 hr
= OLE_CALL_ARGS(priv
->pVideoProcAmp
, GetRange
, control
,
1616 &lMin
, &lMax
, &lStepping
, &lDefault
, &lFlags
);
1617 if (FAILED(hr
) || lFlags
!= VideoProcAmp_Flags_Manual
)
1618 return TVI_CONTROL_FALSE
;
1620 lValue
= lMin
+ (value
+ 100) * (lMax
- lMin
) / 200;
1622 Workaround for ATI AIW 7500. The driver reports: max=255, stepping=256
1624 if (lStepping
> lMax
) {
1625 mp_msg(MSGT_TV
, MSGL_DBG3
,
1626 "tvi_dshow: Stepping (%ld) is bigger than max value (%ld) for control %d. Assuming 1\n",
1627 lStepping
, lMax
,control
);
1630 lValue
-= lValue
% lStepping
;
1631 hr
= OLE_CALL_ARGS(priv
->pVideoProcAmp
, Set
, control
, lValue
,
1632 VideoProcAmp_Flags_Manual
);
1634 return TVI_CONTROL_FALSE
;
1636 return TVI_CONTROL_TRUE
;
1640 * \brief get current value of video control (hue,saturation,contrast,brightess)
1642 * \param priv driver's private data
1643 * \param control which control to adjust
1644 * \param pvalue address of variable thar receives current value
1646 * \return TVI_CONTROL_TRUE success
1647 * \return TVI_CONTROL_FALSE error
1649 static int get_control(priv_t
* priv
, int control
, int *pvalue
)
1651 long lMin
, lMax
, lStepping
, lDefault
, lFlags
, lValue
;
1654 mp_msg(MSGT_TV
, MSGL_DBG4
, "tvi_dshow: get_control called\n");
1655 if (!pvalue
|| !priv
->pVideoProcAmp
)
1656 return TVI_CONTROL_FALSE
;
1658 hr
= OLE_CALL_ARGS(priv
->pVideoProcAmp
, GetRange
, control
,
1659 &lMin
, &lMax
, &lStepping
, &lDefault
, &lFlags
);
1661 return TVI_CONTROL_FALSE
;
1664 return TVI_CONTROL_TRUE
;
1667 hr
= OLE_CALL_ARGS(priv
->pVideoProcAmp
, Get
, control
, &lValue
, &lFlags
);
1669 return TVI_CONTROL_FALSE
;
1671 *pvalue
= 200 * (lValue
- lMin
) / (lMax
- lMin
) - 100;
1673 return TVI_CONTROL_TRUE
;
1677 * \brief create AM_MEDIA_TYPE structure, corresponding to given FourCC code and width/height/fps
1678 * \param fcc FourCC code for video format
1679 * \param width picture width
1680 * \param height pciture height
1681 * \param fps frames per second (required for bitrate calculation)
1683 * \return pointer to AM_MEDIA_TYPE structure if success, NULL - otherwise
1685 static AM_MEDIA_TYPE
* create_video_format(int fcc
, int width
, int height
, int fps
)
1689 VIDEOINFOHEADER vHdr
;
1691 /* Check given fcc in lookup table*/
1692 for(i
=0; img_fmt_list
[i
].fmt
&& img_fmt_list
[i
].fmt
!=fcc
; i
++) /* NOTHING */;
1693 if(!img_fmt_list
[i
].fmt
)
1696 memset(&mt
, 0, sizeof(AM_MEDIA_TYPE
));
1697 memset(&vHdr
, 0, sizeof(VIDEOINFOHEADER
));
1699 vHdr
.bmiHeader
.biSize
= sizeof(vHdr
.bmiHeader
);
1700 vHdr
.bmiHeader
.biWidth
= width
;
1701 vHdr
.bmiHeader
.biHeight
= height
;
1702 //FIXME: is biPlanes required too?
1703 //vHdr.bmiHeader.biPlanes = img_fmt_list[i].nPlanes;
1704 vHdr
.bmiHeader
.biBitCount
= img_fmt_list
[i
].nBits
;
1705 vHdr
.bmiHeader
.biCompression
= img_fmt_list
[i
].nCompression
;
1706 vHdr
.bmiHeader
.biSizeImage
= width
* height
* img_fmt_list
[i
].nBits
/ 8;
1707 vHdr
.dwBitRate
= vHdr
.bmiHeader
.biSizeImage
* 8 * fps
;
1709 mt
.pbFormat
= (char*)&vHdr
;
1710 mt
.cbFormat
= sizeof(vHdr
);
1712 mt
.majortype
= MEDIATYPE_Video
;
1713 mt
.subtype
= *img_fmt_list
[i
].subtype
;
1714 mt
.formattype
= FORMAT_VideoInfo
;
1716 mt
.bFixedSizeSamples
= 1;
1717 mt
.bTemporalCompression
= 0;
1718 mt
.lSampleSize
= vHdr
.bmiHeader
.biSizeImage
;
1720 return CreateMediaType(&mt
);
1724 * \brief extracts fcc,width,height from AM_MEDIA_TYPE
1726 * \param pmt pointer to AM_MEDIA_TYPE to extract data from
1727 * \param pfcc address of variable that receives FourCC
1728 * \param pwidth address of variable that receives width
1729 * \param pheight address of variable that recevies height
1731 * \return 1 if data extracted successfully, 0 - otherwise
1733 static int extract_video_format(AM_MEDIA_TYPE
* pmt
, int *pfcc
,
1734 int *pwidth
, int *pheight
)
1736 mp_msg(MSGT_TV
, MSGL_DBG4
, "tvi_dshow: extract_video_format called\n");
1741 if (memcmp(&(pmt
->formattype
), &FORMAT_VideoInfo
, 16) != 0)
1744 *pfcc
= subtype2imgfmt(&(pmt
->subtype
));
1746 *pwidth
= ((VIDEOINFOHEADER
*) pmt
->pbFormat
)->bmiHeader
.biWidth
;
1748 *pheight
= ((VIDEOINFOHEADER
*) pmt
->pbFormat
)->bmiHeader
.biHeight
;
1753 * \brief extracts samplerate,bits,channels from AM_MEDIA_TYPE
1755 * \param pmt pointer to AM_MEDIA_TYPE to extract data from
1756 * \param pfcc address of variable that receives samplerate
1757 * \param pwidth address of variable that receives number of bits per sample
1758 * \param pheight address of variable that recevies number of channels
1760 * \return 1 if data extracted successfully, 0 - otherwise
1762 static int extract_audio_format(AM_MEDIA_TYPE
* pmt
, int *psamplerate
,
1763 int *pbits
, int *pchannels
)
1765 mp_msg(MSGT_TV
, MSGL_DBG4
, "tvi_dshow: extract_audio_format called\n");
1770 if (memcmp(&(pmt
->formattype
), &FORMAT_WaveFormatEx
, 16) != 0)
1773 *psamplerate
= ((WAVEFORMATEX
*) pmt
->pbFormat
)->nSamplesPerSec
;
1775 *pbits
= ((WAVEFORMATEX
*) pmt
->pbFormat
)->wBitsPerSample
;
1777 *pchannels
= ((WAVEFORMATEX
*) pmt
->pbFormat
)->nChannels
;
1782 * \brief checks if AM_MEDIA_TYPE compatible with given samplerate,bits,channels
1784 * \param pmt pointer to AM_MEDIA_TYPE for check
1785 * \param samplerate audio samplerate
1786 * \param bits bits per sample
1787 * \param channels number of audio channels
1789 * \return 1 if AM_MEDIA_TYPE compatible
1792 static int check_audio_format(AM_MEDIA_TYPE
* pmt
, int samplerate
,
1793 int bits
, int channels
)
1795 mp_msg(MSGT_TV
, MSGL_DBG4
, "tvi_dshow: check_audio_format called\n");
1798 if (memcmp(&(pmt
->majortype
), &MEDIATYPE_Audio
, 16) != 0)
1800 if (memcmp(&(pmt
->subtype
), &MEDIASUBTYPE_PCM
, 16) != 0)
1802 if (memcmp(&(pmt
->formattype
), &FORMAT_WaveFormatEx
, 16) != 0)
1806 if (((WAVEFORMATEX
*) pmt
->pbFormat
)->nSamplesPerSec
!= samplerate
)
1808 if (((WAVEFORMATEX
*) pmt
->pbFormat
)->wBitsPerSample
!= bits
)
1811 && ((WAVEFORMATEX
*) pmt
->pbFormat
)->nChannels
!= channels
)
1818 * \brief checks if AM_MEDIA_TYPE compatible with given fcc,width,height
1820 * \param pmt pointer to AM_MEDIA_TYPE for check
1821 * \param fcc FourCC (compression)
1822 * \param width width of picture
1823 * \param height height of picture
1825 * \return 1 if AM_MEDIA_TYPE compatible
1829 * width and height are currently not used
1832 * add width/height check
1834 static int check_video_format(AM_MEDIA_TYPE
* pmt
, int fcc
, int width
,
1837 mp_msg(MSGT_TV
, MSGL_DBG4
, "tvi_dshow: check_video_format called\n");
1840 if (memcmp(&(pmt
->majortype
), &MEDIATYPE_Video
, 16) != 0)
1842 if (subtype2imgfmt(&(pmt
->subtype
)) != fcc
)
1848 * \brief converts DirectShow subtype to MPlayer's IMGFMT
1850 * \param subtype DirectShow subtype for video format
1852 * \return MPlayer's IMGFMT or 0 if error occured
1854 static int subtype2imgfmt(const GUID
* subtype
)
1857 for (i
= 0; img_fmt_list
[i
].fmt
; i
++) {
1858 if (memcmp(subtype
, img_fmt_list
[i
].subtype
, 16) == 0)
1859 return img_fmt_list
[i
].fmt
;
1865 * \brief prints filter name and it pins
1867 * \param pFilter - IBaseFilter to get data from
1869 * \return S_OK if success, error code otherwise
1871 static HRESULT
show_filter_info(IBaseFilter
* pFilter
)
1875 LPENUMPINS pEnum
= 0;
1877 PIN_DIRECTION ThisPinDir
;
1882 mp_msg(MSGT_TV
, MSGL_DBG4
, "tvi_dshow: show_filter_info called\n");
1883 memset(&fi
, 0, sizeof(fi
));
1884 memset(tmp
, 0, 200);
1886 OLE_CALL_ARGS(pFilter
, QueryFilterInfo
, &fi
);
1887 OLE_RELEASE_SAFE(fi
.pGraph
);
1888 wtoa(fi
.achName
, tmp
, 200);
1889 mp_msg(MSGT_TV
, MSGL_DBG2
, "tvi_dshow: BaseFilter (%p): Name=%s, Graph=%p output pins:",
1890 pFilter
, tmp
, fi
.pGraph
);
1891 hr
= OLE_CALL_ARGS(pFilter
, EnumPins
, &pEnum
);
1895 while (OLE_CALL_ARGS(pEnum
, Next
, 1, &pPin
, NULL
) == S_OK
) {
1896 memset(&pi
, 0, sizeof(pi
));
1897 memset(tmp
, 0, 200);
1898 OLE_CALL_ARGS(pPin
, QueryDirection
, &ThisPinDir
);
1899 if (ThisPinDir
== PINDIR_OUTPUT
) {
1900 OLE_CALL_ARGS(pPin
, QueryPinInfo
, &pi
);
1901 wtoa(pi
.achName
, tmp
, 200);
1902 OLE_RELEASE_SAFE(pi
.pFilter
);
1903 mp_msg(MSGT_TV
, MSGL_DBG2
, " %d=%s", i
, tmp
);
1904 mp_msg(MSGT_TV
, MSGL_DBG3
, " (%p)", pPin
);
1905 mp_msg(MSGT_TV
, MSGL_DBG2
, ";");
1906 OLE_RELEASE_SAFE(pPin
);
1910 mp_msg(MSGT_TV
, MSGL_DBG2
, "\n");
1911 OLE_RELEASE_SAFE(pEnum
);
1916 * \brief gets device's frendly in ANSI encoding
1918 * \param pM IMoniker interface, got in enumeration process
1919 * \param category device category
1921 * \return TVI_CONTROL_TRUE if operation succeded, TVI_CONTROL_FALSE - otherwise
1923 static int get_device_name(IMoniker
* pM
, char *pBuf
, int nLen
)
1927 IPropertyBag
*pPropBag
;
1928 hr
= OLE_CALL_ARGS(pM
, BindToStorage
, 0, 0, &IID_IPropertyBag
,(void *) &pPropBag
);
1930 mp_msg(MSGT_TV
, MSGL_DBG2
, "tvi_dshow: Call to BindToStorage failed\n");
1931 return TVI_CONTROL_FALSE
;
1934 hr
= OLE_CALL_ARGS(pPropBag
, Read
, L
"Description", (LPVARIANT
) & var
,
1937 hr
= OLE_CALL_ARGS(pPropBag
, Read
, L
"FriendlyName", (LPVARIANT
) & var
,
1940 OLE_RELEASE_SAFE(pPropBag
);
1941 if (SUCCEEDED(hr
)) {
1942 wtoa(var
.bstrVal
, pBuf
, nLen
);
1943 return TVI_CONTROL_TRUE
;
1945 return TVI_CONTROL_FALSE
;
1949 * \brief find capture device at given index
1951 * \param index device index to search for (-1 mean only print available)
1952 * \param category device category
1954 * \return IBaseFilter interface for capture device with given index
1956 * Sample values for category:
1957 * CLSID_VideoInputDeviceCategory - Video Capture Sources
1958 * CLSID_AudioInputDeviceCategory - Audio Capture Sources
1959 * See DirectShow SDK documentation for other possible values
1961 static IBaseFilter
*find_capture_device(int index
, REFCLSID category
)
1963 IBaseFilter
*pFilter
= NULL
;
1964 ICreateDevEnum
*pDevEnum
= NULL
;
1965 IEnumMoniker
*pClassEnum
= NULL
;
1970 char tmp
[DEVICE_NAME_MAX_LEN
+ 1];
1971 hr
= CoCreateInstance((GUID
*) & CLSID_SystemDeviceEnum
, NULL
,
1972 CLSCTX_INPROC_SERVER
, &IID_ICreateDevEnum
,
1973 (void *) &pDevEnum
);
1975 mp_msg(MSGT_TV
, MSGL_DBG2
, "tvi_dshow: Unable to create device enumerator\n");
1979 hr
= OLE_CALL_ARGS(pDevEnum
, CreateClassEnumerator
, category
, &pClassEnum
, 0);
1980 OLE_RELEASE_SAFE(pDevEnum
);
1982 mp_msg(MSGT_TV
, MSGL_DBG2
, "tvi_dshow: Unable to create class enumerator\n");
1985 if (hr
== S_FALSE
) {
1986 mp_msg(MSGT_TV
, MSGL_DBG2
, "tvi_dshow: No capture devices found\n");
1990 OLE_CALL(pClassEnum
,Reset
);
1991 for (i
= 0; OLE_CALL_ARGS(pClassEnum
, Next
, 1, &pM
, &cFetched
) == S_OK
; i
++) {
1992 if(get_device_name(pM
, tmp
, DEVICE_NAME_MAX_LEN
)!=TVI_CONTROL_TRUE
)
1993 mp_msg(MSGT_TV
, MSGL_ERR
, MSGTR_TVI_DS_UnableGetDeviceName
, i
);
1995 mp_msg(MSGT_TV
, MSGL_V
, MSGTR_TVI_DS_DeviceName
, i
, tmp
);
1996 if (index
!= -1 && i
== index
) {
1997 mp_msg(MSGT_TV
, MSGL_INFO
, MSGTR_TVI_DS_UsingDevice
, index
, tmp
);
1998 hr
= OLE_CALL_ARGS(pM
, BindToObject
, 0, 0, &IID_IBaseFilter
,(void *) &pFilter
);
2002 OLE_RELEASE_SAFE(pM
);
2004 if (index
!= -1 && !pFilter
) {
2005 mp_msg(MSGT_TV
, MSGL_ERR
, MSGTR_TVI_DS_DeviceNotFound
,
2008 OLE_RELEASE_SAFE(pClassEnum
);
2014 * \brief get array of available formats through call to IAMStreamConfig::GetStreamCaps
2016 * \praram[in] chain chain data structure
2018 * \return S_OK success
2019 * \return E_POINTER one of parameters is NULL
2020 * \return E_FAIL required size of buffer is unknown for given media type
2021 * \return E_OUTOFMEMORY not enough memory
2022 * \return other error code from called methods
2025 * last items of chain->arpmt and chain->arStreamCaps will be NULL
2027 static HRESULT
get_available_formats_stream(chain_t
*chain
)
2029 AM_MEDIA_TYPE
**arpmt
;
2036 mp_msg(MSGT_TV
, MSGL_DBG4
,
2037 "tvi_dshow: get_available_formats_stream called\n");
2039 if (!chain
->pStreamConfig
)
2042 hr
=OLE_CALL_ARGS(chain
->pStreamConfig
, GetNumberOfCapabilities
, &count
, &size
);
2044 mp_msg(MSGT_TV
, MSGL_DBG4
,
2045 "tvi_dshow: Call to GetNumberOfCapabilities failed (get_available_formats_stream)\n");
2048 if (chain
->type
== video
){
2049 if (size
!= sizeof(VIDEO_STREAM_CONFIG_CAPS
)) {
2050 mp_msg(MSGT_TV
, MSGL_DBG4
,
2051 "tvi_dshow: Wrong video structure size for GetNumberOfCapabilities (get_available_formats_stream)\n");
2054 } else if (chain
->type
== audio
){
2055 if (size
!= sizeof(AUDIO_STREAM_CONFIG_CAPS
)) {
2056 mp_msg(MSGT_TV
, MSGL_DBG4
,
2057 "tvi_dshow: Wrong audio structure size for GetNumberOfCapabilities (get_available_formats_stream)\n");
2061 mp_msg(MSGT_TV
, MSGL_ERR
, MSGTR_TVI_DS_UnsupportedMediaType
,"get_available_formats_stream");
2066 arpmt
= malloc((count
+ 1) * sizeof(AM_MEDIA_TYPE
*));
2068 memset(arpmt
, 0, (count
+ 1) * sizeof(AM_MEDIA_TYPE
*));
2070 pBuf
= malloc((count
+ 1) * sizeof(void *));
2072 memset(pBuf
, 0, (count
+ 1) * sizeof(void *));
2074 for (i
= 0; i
< count
; i
++) {
2075 pBuf
[i
] = malloc(size
);
2080 hr
= OLE_CALL_ARGS(chain
->pStreamConfig
, GetStreamCaps
, i
,
2081 &(arpmt
[i
]), pBuf
[i
]);
2086 chain
->arpmt
= arpmt
;
2087 chain
->arStreamCaps
= pBuf
;
2093 for (i
= 0; i
< count
; i
++) {
2094 if (pBuf
&& pBuf
[i
])
2096 if (arpmt
&& arpmt
[i
])
2097 DeleteMediaType(arpmt
[i
]);
2104 mp_msg(MSGT_TV
, MSGL_DBG4
, "tvi_dshow: Call to GetStreamCaps failed (get_available_formats_stream)\n");
2107 return E_OUTOFMEMORY
;
2113 * \brief returns allocates an array and store available media formats for given pin type to it
2115 * \param pBuilder ICaptureGraphBuilder2 interface of graph builder
2116 * \param chain chain data structure
2118 * \return S_OK success
2119 * \return E_POINTER one of given pointers is null
2120 * \return apropriate error code otherwise
2122 static HRESULT
get_available_formats_pin(ICaptureGraphBuilder2
* pBuilder
,
2125 IEnumMediaTypes
*pEnum
;
2131 AM_MEDIA_TYPE
**arpmt
; //This will be real array
2132 VIDEO_STREAM_CONFIG_CAPS
*pVideoCaps
;
2133 AUDIO_STREAM_CONFIG_CAPS
*pAudioCaps
;
2136 mp_msg(MSGT_TV
, MSGL_DBG4
,
2137 "tvi_dshow: get_available_formats_pin called\n");
2138 if (!pBuilder
|| !chain
->pCaptureFilter
)
2141 if (!chain
->pCapturePin
)
2143 hr
= OLE_CALL_ARGS(pBuilder
, FindPin
,
2144 (IUnknown
*) chain
->pCaptureFilter
,
2145 PINDIR_OUTPUT
, &PIN_CATEGORY_CAPTURE
,
2146 chain
->majortype
, FALSE
, 0, &chain
->pCapturePin
);
2148 if (!chain
->pCapturePin
)
2151 if (chain
->type
== video
) {
2152 size
= sizeof(VIDEO_STREAM_CONFIG_CAPS
);
2153 } else if (chain
->type
== audio
) {
2154 size
= sizeof(AUDIO_STREAM_CONFIG_CAPS
);
2156 mp_msg(MSGT_TV
, MSGL_ERR
, MSGTR_TVI_DS_UnsupportedMediaType
,"get_available_formats_pin");
2160 hr
= OLE_CALL_ARGS(chain
->pCapturePin
, EnumMediaTypes
, &pEnum
);
2162 mp_msg(MSGT_TV
, MSGL_DBG4
,
2163 "tvi_dshow: Call to EnumMediaTypes failed (get_available_formats_pin)\n");
2166 for (i
= 0; OLE_CALL_ARGS(pEnum
, Next
, 1, &pmt
, &cFetched
) == S_OK
; i
++) {
2170 OLE_CALL(pEnum
,Reset
);
2173 arpmt
= malloc((count
+ 1) * sizeof(AM_MEDIA_TYPE
*));
2175 return E_OUTOFMEMORY
;
2176 memset(arpmt
, 0, (count
+ 1) * sizeof(AM_MEDIA_TYPE
*));
2180 && OLE_CALL_ARGS(pEnum
, Next
, 1, &(arpmt
[i
]), &cFetched
) == S_OK
;
2183 OLE_RELEASE_SAFE(pEnum
);
2186 pBuf
= malloc((count
+ 1) * sizeof(void *));
2188 for (i
= 0; i
< count
; i
++)
2190 DeleteMediaType(arpmt
[i
]);
2192 return E_OUTOFMEMORY
;
2194 memset(pBuf
, 0, (count
+ 1) * sizeof(void *));
2196 for (i
= 0; i
< count
; i
++) {
2197 pBuf
[i
] = malloc(size
);
2200 memset(pBuf
[i
], 0, size
);
2202 if (chain
->type
== video
) {
2203 pVideoCaps
= (VIDEO_STREAM_CONFIG_CAPS
*) pBuf
[i
];
2204 extract_video_format(arpmt
[i
], NULL
, &p1
, &p2
);
2205 pVideoCaps
->MaxOutputSize
.cx
= pVideoCaps
->MinOutputSize
.cx
=
2207 pVideoCaps
->MaxOutputSize
.cy
= pVideoCaps
->MinOutputSize
.cy
=
2210 pAudioCaps
= (AUDIO_STREAM_CONFIG_CAPS
*) pBuf
[i
];
2211 extract_audio_format(arpmt
[i
], &p1
, &p2
, &p3
);
2212 pAudioCaps
->MaximumSampleFrequency
=
2213 pAudioCaps
->MinimumSampleFrequency
= p1
;
2214 pAudioCaps
->MaximumBitsPerSample
=
2215 pAudioCaps
->MinimumBitsPerSample
= p2
;
2216 pAudioCaps
->MaximumChannels
= pAudioCaps
->MinimumChannels
= p3
;
2221 for (i
= 0; i
< count
; i
++) {
2223 DeleteMediaType(arpmt
[i
]);
2229 return E_OUTOFMEMORY
;
2231 chain
->arpmt
= arpmt
;
2232 chain
->arStreamCaps
= pBuf
;
2238 *---------------------------------------------------------------------------------------
2242 *---------------------------------------------------------------------------------------
2245 * \brief fills given buffer with audio data (usually one block)
2247 * \param priv driver's private data structure
2248 * \param buffer buffer to store data to
2249 * \param len buffer's size in bytes (usually one block size)
2251 * \return audio pts if audio present, 1 - otherwise
2253 static double grab_audio_frame(priv_t
* priv
, char *buffer
, int len
)
2258 grabber_ringbuffer_t
*rb
= priv
->chains
[1]->rbuf
;
2259 grabber_ringbuffer_t
*vrb
= priv
->chains
[0]->rbuf
;
2261 if (!rb
|| !rb
->ringbuffer
)
2264 if(vrb
&& vrb
->tStart
<0){
2265 memset(buffer
,0,len
);
2268 if(vrb
&& rb
->tStart
<0)
2269 rb
->tStart
=vrb
->tStart
;
2271 if (len
< rb
->blocksize
)
2274 bytes
= rb
->blocksize
;
2276 mp_msg(MSGT_TV
, MSGL_DBG3
,"tvi_dshow: FillBuffer (audio) called. %d blocks in buffer, %d bytes requested\n",
2279 mp_msg(MSGT_TV
,MSGL_DBG4
,"tvi_dshow: waiting for frame\n");
2280 for(i
=0;i
<1000 && !rb
->count
;i
++) usec_sleep(1000);
2282 mp_msg(MSGT_TV
,MSGL_DBG4
,"tvi_dshow: waiting timeout\n");
2285 mp_msg(MSGT_TV
,MSGL_DBG4
,"tvi_dshow: got frame!\n");
2288 EnterCriticalSection(rb
->pMutex
);
2289 pts
=rb
->dpts
[rb
->head
]-rb
->tStart
;
2290 memcpy(buffer
, rb
->ringbuffer
[rb
->head
], bytes
);
2291 rb
->head
= (rb
->head
+ 1) % rb
->buffersize
;
2293 LeaveCriticalSection(rb
->pMutex
);
2298 * \brief returns audio frame size
2300 * \param priv driver's private data structure
2302 * \return audio block size if audio enabled and 1 - otherwise
2304 static int get_audio_framesize(priv_t
* priv
)
2306 if (!priv
->chains
[1]->rbuf
)
2307 return 1; //no audio
2308 mp_msg(MSGT_TV
,MSGL_DBG3
,"get_audio_framesize: %d\n",priv
->chains
[1]->rbuf
->blocksize
);
2309 return priv
->chains
[1]->rbuf
->blocksize
;
2312 static int vbi_get_props(priv_t
* priv
,tt_stream_props
* ptsp
)
2315 return TVI_CONTROL_FALSE
;
2321 ptsp
->sampling_rate
=27e6
;
2322 ptsp
->samples_per_line
=720;
2327 ptsp
->bufsize
= ptsp
->samples_per_line
* (ptsp
->count
[0] + ptsp
->count
[1]);
2329 mp_msg(MSGT_TV
,MSGL_V
,"vbi_get_props: sampling_rate=%d,offset:%d,samples_per_line: %d\n interlaced:%s, count=[%d,%d]\n",
2330 ptsp
->sampling_rate
,
2332 ptsp
->samples_per_line
,
2333 ptsp
->interlaced
?"Yes":"No",
2337 return TVI_CONTROL_TRUE
;
2340 static void vbi_grabber(priv_t
* priv
)
2342 grabber_ringbuffer_t
*rb
= priv
->chains
[2]->rbuf
;
2345 if (!rb
|| !rb
->ringbuffer
)
2348 buf
=calloc(1,rb
->blocksize
);
2349 for(i
=0; i
<23 && rb
->count
; i
++){
2350 memcpy(buf
,rb
->ringbuffer
[rb
->head
],rb
->blocksize
);
2351 teletext_control(priv
->priv_vbi
,TV_VBI_CONTROL_DECODE_PAGE
,&buf
);
2352 rb
->head
= (rb
->head
+ 1) % rb
->buffersize
;
2359 * \brief fills given buffer with video data (usually one frame)
2361 * \param priv driver's private data structure
2362 * \param buffer buffer to store data to
2363 * \param len buffer's size in bytes (usually one frame size)
2365 * \return frame size if video present, 0 - otherwise
2367 static double grab_video_frame(priv_t
* priv
, char *buffer
, int len
)
2372 grabber_ringbuffer_t
*rb
= priv
->chains
[0]->rbuf
;
2374 if (!rb
|| !rb
->ringbuffer
)
2376 if (len
< rb
->blocksize
)
2379 bytes
= rb
->blocksize
;
2381 mp_msg(MSGT_TV
, MSGL_DBG3
,"tvi_dshow: FillBuffer (video) called. %d blocks in buffer, %d bytes requested\n",
2384 mp_msg(MSGT_TV
,MSGL_DBG4
,"tvi_dshow: waiting for frame\n");
2385 for(i
=0;i
<1000 && !rb
->count
;i
++) usec_sleep(1000);
2387 mp_msg(MSGT_TV
,MSGL_DBG4
,"tvi_dshow: waiting timeout\n");
2390 mp_msg(MSGT_TV
,MSGL_DBG4
,"tvi_dshow: got frame!\n");
2392 EnterCriticalSection(rb
->pMutex
);
2394 rb
->tStart
=rb
->dpts
[rb
->head
];
2395 pts
=rb
->dpts
[rb
->head
]-rb
->tStart
;
2396 memcpy(buffer
, rb
->ringbuffer
[rb
->head
], bytes
);
2397 rb
->head
= (rb
->head
+ 1) % rb
->buffersize
;
2399 LeaveCriticalSection(rb
->pMutex
);
2406 * \brief returns frame size
2408 * \param priv driver's private data structure
2410 * \return frame size if video present, 0 - otherwise
2412 static int get_video_framesize(priv_t
* priv
)
2414 // if(!priv->pmtVideo) return 1; //no video
2415 // return priv->pmtVideo->lSampleSize;
2416 if (!priv
->chains
[0]->rbuf
)
2417 return 1; //no video
2418 mp_msg(MSGT_TV
,MSGL_DBG3
,"geT_video_framesize: %d\n",priv
->chains
[0]->rbuf
->blocksize
);
2419 return priv
->chains
[0]->rbuf
->blocksize
;
2423 * \brief calculate audio buffer size
2424 * \param video_buf_size size of video buffer in bytes
2425 * \param video_bitrate video bit rate
2426 * \param audio_bitrate audio bit rate
2427 * \return audio buffer isze in bytes
2429 * \remarks length of video buffer and resulted audio buffer calculated in
2430 * seconds will be the same.
2432 static inline int audio_buf_size_from_video(int video_buf_size
, int video_bitrate
, int audio_bitrate
)
2434 int audio_buf_size
= audio_bitrate
* (video_buf_size
/ video_bitrate
);
2435 mp_msg(MSGT_TV
,MSGL_DBG2
,"tvi_dshow: Audio capture buffer: %d * %d / %d = %d\n",
2436 audio_bitrate
,video_buf_size
,video_bitrate
,audio_buf_size
);
2437 return audio_buf_size
;
2441 * \brief common chain initialization routine
2442 * \param chain chain data structure
2444 * \note pCaptureFilter member should be initialized before call to this routine
2446 static HRESULT
init_chain_common(ICaptureGraphBuilder2
*pBuilder
, chain_t
*chain
)
2451 if(!chain
->pCaptureFilter
)
2454 show_filter_info(chain
->pCaptureFilter
);
2456 hr
= OLE_CALL_ARGS(pBuilder
, FindPin
,
2457 (IUnknown
*) chain
->pCaptureFilter
,
2458 PINDIR_OUTPUT
, chain
->pin_category
,
2459 chain
->majortype
, FALSE
, 0, &chain
->pCapturePin
);
2462 mp_msg(MSGT_TV
,MSGL_DBG2
, "tvi_dshow: FindPin(pCapturePin) call failed. Error:0x%x\n", (unsigned int)hr
);
2466 hr
= OLE_CALL_ARGS(pBuilder
, FindInterface
,
2467 chain
->pin_category
,
2469 chain
->pCaptureFilter
,
2470 &IID_IAMStreamConfig
,
2471 (void **) &(chain
->pStreamConfig
));
2473 chain
->pStreamConfig
= NULL
;
2476 Getting available video formats (last pointer in array will be NULL)
2477 First tryin to call IAMStreamConfig::GetStreamCaos. this will give us additional information such as
2478 min/max picture dimensions, etc. If this call fails trying IPIn::EnumMediaTypes with default
2481 hr
= get_available_formats_stream(chain
);
2483 mp_msg(MSGT_TV
, MSGL_DBG2
, "Unable to use IAMStreamConfig for retriving available formats (Error:0x%x). Using EnumMediaTypes instead\n", (unsigned int)hr
);
2484 hr
= get_available_formats_pin(pBuilder
, chain
);
2489 chain
->nFormatUsed
= 0;
2491 //If argument to CreateMediaType is NULL then result will be NULL too.
2492 chain
->pmt
= CreateMediaType(chain
->arpmt
[0]);
2494 for (i
= 0; chain
->arpmt
[i
]; i
++)
2495 DisplayMediaType("Available format", chain
->arpmt
[i
]);
2500 * \brief build video stream chain in graph
2501 * \param priv private data structure
2503 * \return S_OK if chain was built successfully, apropriate error code otherwise
2505 static HRESULT
build_video_chain(priv_t
*priv
)
2509 if(priv
->chains
[0]->rbuf
)
2512 if (priv
->chains
[0]->pStreamConfig
) {
2513 hr
= OLE_CALL_ARGS(priv
->chains
[0]->pStreamConfig
, SetFormat
, priv
->chains
[0]->pmt
);
2515 mp_msg(MSGT_TV
,MSGL_ERR
,MSGTR_TVI_DS_UnableSelectVideoFormat
, (unsigned int)hr
);
2519 priv
->chains
[0]->rbuf
=calloc(1,sizeof(grabber_ringbuffer_t
));
2520 if(!priv
->chains
[0]->rbuf
)
2521 return E_OUTOFMEMORY
;
2523 if (priv
->tv_param
->buffer_size
>= 0) {
2524 priv
->chains
[0]->rbuf
->buffersize
= priv
->tv_param
->buffer_size
;
2526 priv
->chains
[0]->rbuf
->buffersize
= 16;
2529 priv
->chains
[0]->rbuf
->buffersize
*= 1024 * 1024;
2530 hr
=build_sub_graph(priv
, priv
->chains
[0], &PIN_CATEGORY_CAPTURE
);
2532 mp_msg(MSGT_TV
, MSGL_ERR
, MSGTR_TVI_DS_UnableBuildVideoSubGraph
,(unsigned int)hr
);
2539 * \brief build audio stream chain in graph
2540 * \param priv private data structure
2542 * \return S_OK if chain was built successfully, apropriate error code otherwise
2544 static HRESULT
build_audio_chain(priv_t
*priv
)
2548 if(priv
->chains
[1]->rbuf
)
2551 if(priv
->immediate_mode
)
2554 if (priv
->chains
[1]->pStreamConfig
) {
2555 hr
= OLE_CALL_ARGS(priv
->chains
[1]->pStreamConfig
, SetFormat
,
2556 priv
->chains
[1]->pmt
);
2558 mp_msg(MSGT_TV
,MSGL_ERR
,MSGTR_TVI_DS_UnableSelectAudioFormat
, (unsigned int)hr
);
2562 if(priv
->chains
[1]->pmt
){
2563 priv
->chains
[1]->rbuf
=calloc(1,sizeof(grabber_ringbuffer_t
));
2564 if(!priv
->chains
[1]->rbuf
)
2565 return E_OUTOFMEMORY
;
2567 /* let the audio buffer be the same size (in seconds) than video one */
2568 priv
->chains
[1]->rbuf
->buffersize
=audio_buf_size_from_video(
2569 priv
->chains
[0]->rbuf
->buffersize
,
2570 (((VIDEOINFOHEADER
*) priv
->chains
[0]->pmt
->pbFormat
)->dwBitRate
),
2571 (((WAVEFORMATEX
*) (priv
->chains
[1]->pmt
->pbFormat
))->nAvgBytesPerSec
));
2573 hr
=build_sub_graph(priv
, priv
->chains
[1],&PIN_CATEGORY_CAPTURE
);
2575 mp_msg(MSGT_TV
, MSGL_ERR
, MSGTR_TVI_DS_UnableBuildAudioSubGraph
,(unsigned int)hr
);
2583 * \brief build VBI stream chain in graph
2584 * \param priv private data structure
2586 * \return S_OK if chain was built successfully, apropriate error code otherwise
2588 static HRESULT
build_vbi_chain(priv_t
*priv
)
2592 if(priv
->chains
[2]->rbuf
)
2595 if(priv
->tv_param
->teletext
.device
)
2597 priv
->chains
[2]->rbuf
=calloc(1,sizeof(grabber_ringbuffer_t
));
2598 if(!priv
->chains
[2]->rbuf
)
2599 return E_OUTOFMEMORY
;
2601 init_ringbuffer(priv
->chains
[2]->rbuf
,24,priv
->tsp
.bufsize
);
2603 hr
=build_sub_graph(priv
, priv
->chains
[2],&PIN_CATEGORY_VBI
);
2605 mp_msg(MSGT_TV
, MSGL_ERR
, MSGTR_TVI_DS_UnableBuildVBISubGraph
,(unsigned int)hr
);
2613 * \brief playback/capture real start
2615 * \param priv driver's private data structure
2617 * \return 1 if success, 0 - otherwise
2619 * TODO: move some code from init() here
2621 static int start(priv_t
* priv
)
2625 hr
= build_video_chain(priv
);
2629 hr
= build_audio_chain(priv
);
2633 hr
= build_vbi_chain(priv
);
2638 Graph is ready to capture. Starting graph.
2640 if (mp_msg_test(MSGT_TV
, MSGL_DBG2
)) {
2641 mp_msg(MSGT_TV
, MSGL_DBG2
, "Debug pause 10sec\n");
2642 usec_sleep(10000000);
2643 mp_msg(MSGT_TV
, MSGL_DBG2
, "Debug pause end\n");
2645 if (!priv
->pMediaControl
) {
2646 mp_msg(MSGT_TV
,MSGL_ERR
,MSGTR_TVI_DS_UnableGetMediaControlInterface
,(unsigned int)E_POINTER
);
2649 hr
= OLE_CALL(priv
->pMediaControl
, Run
);
2651 mp_msg(MSGT_TV
,MSGL_ERR
,MSGTR_TVI_DS_UnableStartGraph
, (unsigned int)hr
);
2654 mp_msg(MSGT_TV
, MSGL_DBG2
, "tvi_dshow: Graph is started.\n");
2661 * \brief driver initialization
2663 * \param priv driver's private data structure
2665 * \return 1 if success, 0 - otherwise
2667 static int init(priv_t
* priv
)
2671 long lInput
, lTunerInput
;
2672 IEnumFilters
*pEnum
;
2673 IBaseFilter
*pFilter
;
2682 priv
->chains
[i
] = calloc(1, sizeof(chain_t
));
2684 priv
->chains
[0]->type
=video
;
2685 priv
->chains
[0]->majortype
=&MEDIATYPE_Video
;
2686 priv
->chains
[0]->pin_category
=&PIN_CATEGORY_CAPTURE
;
2687 priv
->chains
[1]->type
=audio
;
2688 priv
->chains
[1]->majortype
=&MEDIATYPE_Audio
;
2689 priv
->chains
[1]->pin_category
=&PIN_CATEGORY_CAPTURE
;
2690 priv
->chains
[2]->type
=vbi
;
2691 priv
->chains
[2]->majortype
=&MEDIATYPE_VBI
;
2692 priv
->chains
[2]->pin_category
=&PIN_CATEGORY_VBI
;
2695 hr
= CoCreateInstance((GUID
*) & CLSID_FilterGraph
, NULL
,
2696 CLSCTX_INPROC_SERVER
, &IID_IGraphBuilder
,
2697 (void **) &priv
->pGraph
);
2699 mp_msg(MSGT_TV
,MSGL_DBG2
, "tvi_dshow: CoCreateInstance(FilterGraph) call failed. Error:0x%x\n", (unsigned int)hr
);
2703 if (mp_msg_test(MSGT_TV
, MSGL_DBG2
)) {
2704 AddToRot((IUnknown
*) priv
->pGraph
, &(priv
->dwRegister
));
2707 hr
= CoCreateInstance((GUID
*) & CLSID_CaptureGraphBuilder2
, NULL
,
2708 CLSCTX_INPROC_SERVER
, &IID_ICaptureGraphBuilder2
,
2709 (void **) &priv
->pBuilder
);
2711 mp_msg(MSGT_TV
,MSGL_DBG2
, "tvi_dshow: CoCreateInstance(CaptureGraphBuilder) call failed. Error:0x%x\n", (unsigned int)hr
);
2715 hr
= OLE_CALL_ARGS(priv
->pBuilder
, SetFiltergraph
, priv
->pGraph
);
2717 mp_msg(MSGT_TV
,MSGL_ERR
, "tvi_dshow: SetFiltergraph call failed. Error:0x%x\n",(unsigned int)hr
);
2721 mp_msg(MSGT_TV
, MSGL_DBG2
, "tvi_dshow: Searching for available video capture devices\n");
2722 priv
->chains
[0]->pCaptureFilter
= find_capture_device(priv
->dev_index
, &CLSID_VideoInputDeviceCategory
);
2723 if(!priv
->chains
[0]->pCaptureFilter
){
2724 mp_msg(MSGT_TV
,MSGL_ERR
, MSGTR_TVI_DS_NoVideoCaptureDevice
);
2727 hr
= OLE_CALL_ARGS(priv
->pGraph
, AddFilter
, priv
->chains
[0]->pCaptureFilter
, NULL
);
2729 mp_msg(MSGT_TV
, MSGL_DBG2
, "tvi_dshow: Unable to add video capture device to Directshow graph. Error:0x%x\n", (unsigned int)hr
);
2732 mp_msg(MSGT_TV
, MSGL_DBG2
, "tvi_dshow: Searching for available audio capture devices\n");
2733 if (priv
->adev_index
!= -1) {
2734 priv
->chains
[1]->pCaptureFilter
= find_capture_device(priv
->adev_index
, &CLSID_AudioInputDeviceCategory
); //output available audio edevices
2735 if(!priv
->chains
[1]->pCaptureFilter
){
2736 mp_msg(MSGT_TV
,MSGL_ERR
, MSGTR_TVI_DS_NoAudioCaptureDevice
);
2740 hr
= OLE_CALL_ARGS(priv
->pGraph
, AddFilter
, priv
->chains
[1]->pCaptureFilter
, NULL
);
2742 mp_msg(MSGT_TV
,MSGL_DBG2
, "tvi_dshow: Unable to add audio capture device to Directshow graph. Error:0x%x\n", (unsigned int)hr
);
2746 hr
= OLE_QUERYINTERFACE(priv
->chains
[0]->pCaptureFilter
, IID_IBaseFilter
, priv
->chains
[1]->pCaptureFilter
);
2748 /* increase refrence counter for capture filter ad store pointer into vbi chain structure too */
2749 hr
= OLE_QUERYINTERFACE(priv
->chains
[0]->pCaptureFilter
, IID_IBaseFilter
, priv
->chains
[2]->pCaptureFilter
);
2751 hr
= OLE_QUERYINTERFACE(priv
->chains
[0]->pCaptureFilter
, IID_IAMVideoProcAmp
,priv
->pVideoProcAmp
);
2752 if (FAILED(hr
) && hr
!= E_NOINTERFACE
)
2753 mp_msg(MSGT_TV
, MSGL_DBG2
, "tvi_dshow: Get IID_IAMVideoProcAmp failed (0x%x).\n", (unsigned int)hr
);
2756 mp_msg(MSGT_TV
, MSGL_INFO
, MSGTR_TVI_DS_VideoAdjustigNotSupported
);
2757 priv
->pVideoProcAmp
= NULL
;
2760 hr
= OLE_CALL_ARGS(priv
->pBuilder
, FindInterface
,
2761 &PIN_CATEGORY_CAPTURE
,
2762 priv
->chains
[0]->majortype
,
2763 priv
->chains
[0]->pCaptureFilter
,
2764 &IID_IAMCrossbar
, (void **) &(priv
->pCrossbar
));
2766 mp_msg(MSGT_TV
, MSGL_INFO
, MSGTR_TVI_DS_SelectingInputNotSupported
);
2767 priv
->pCrossbar
= NULL
;
2770 if (priv
->tv_param
->amode
>= 0) {
2771 IAMTVAudio
*pTVAudio
;
2772 hr
= OLE_CALL_ARGS(priv
->pBuilder
, FindInterface
, NULL
, NULL
,priv
->chains
[0]->pCaptureFilter
,&IID_IAMTVAudio
, (void *) &pTVAudio
);
2774 switch (priv
->tv_param
->amode
) {
2776 hr
= OLE_CALL_ARGS(pTVAudio
, put_TVAudioMode
, AMTVAUDIO_MODE_MONO
);
2779 hr
= OLE_CALL_ARGS(pTVAudio
, put_TVAudioMode
, AMTVAUDIO_MODE_STEREO
);
2782 hr
= OLE_CALL_ARGS(pTVAudio
, put_TVAudioMode
,
2783 AMTVAUDIO_MODE_LANG_A
);
2786 hr
= OLE_CALL_ARGS(pTVAudio
, put_TVAudioMode
,
2787 AMTVAUDIO_MODE_LANG_B
);
2790 OLE_RELEASE_SAFE(pTVAudio
);
2792 mp_msg(MSGT_TV
, MSGL_WARN
, MSGTR_TVI_DS_UnableSetAudioMode
, priv
->tv_param
->amode
,(unsigned int)hr
);
2796 // Video chain initialization
2797 hr
= init_chain_common(priv
->pBuilder
, priv
->chains
[0]);
2802 Audio chain initialization
2803 Since absent audio stream is not fatal,
2804 at least one NULL pointer should be kept in format arrays
2805 (to avoid another additional check everywhere for array presence).
2807 hr
= init_chain_common(priv
->pBuilder
, priv
->chains
[1]);
2810 mp_msg(MSGT_TV
, MSGL_V
, "tvi_dshow: Unable to initialize audio chain (Error:0x%x). Audio disabled\n", (unsigned long)hr
);
2811 priv
->chains
[1]->arpmt
=calloc(1, sizeof(AM_MEDIA_TYPE
*));
2812 priv
->chains
[1]->arStreamCaps
=calloc(1, sizeof(void*));
2816 VBI chain initialization
2817 Since absent VBI stream is not fatal,
2818 at least one NULL pointer should be kept in format arrays
2819 (to avoid another additional check everywhere for array presence).
2821 hr
= init_chain_common(priv
->pBuilder
, priv
->chains
[2]);
2824 mp_msg(MSGT_TV
, MSGL_V
, "tvi_dshow: Unable to initialize VBI chain (Error:0x%x). Teletext disabled\n", (unsigned long)hr
);
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_msg(MSGT_TV
, MSGL_INFO
, MSGTR_TVI_DS_ChangingWidthHeightNotSupported
);
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_msg(MSGT_TV
, MSGL_ERR
, MSGTR_TVI_DS_ErrorParsingVideoFormatStruct
);
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_msg(MSGT_TV
, MSGL_ERR
, MSGTR_TVI_DS_ErrorParsingAudioFormatStruct
);
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_msg(MSGT_TV
,MSGL_ERR
, MSGTR_TVI_DS_UnableGetMediaControlInterface
,(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_msg(MSGT_TV
,MSGL_ERR
, MSGTR_TVI_DS_UnableTerminateVPPin
, (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_msg(MSGT_TV
,MSGL_ERR
, MSGTR_TVI_DS_GraphInitFailure
);
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
)
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_msg(MSGT_TV
, MSGL_ERR
, MSGTR_TVI_DS_WrongDeviceParam
, tv_param
->device
);
3084 if (priv
->dev_index
< 0) {
3085 mp_msg(MSGT_TV
, MSGL_ERR
, MSGTR_TVI_DS_WrongDeviceIndex
, a
);
3090 if (tv_param
->adevice
) {
3091 if (sscanf(tv_param
->adevice
, "%d", &a
) == 1) {
3092 priv
->adev_index
= a
;
3094 mp_msg(MSGT_TV
, MSGL_ERR
, MSGTR_TVI_DS_WrongADeviceParam
, tv_param
->adevice
);
3098 if (priv
->dev_index
< 0) {
3099 mp_msg(MSGT_TV
, MSGL_ERR
, MSGTR_TVI_DS_WrongADeviceIndex
, 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_msg(MSGT_TV
, MSGL_WARN
, MSGTR_TVI_DS_SamplerateNotsupported
, 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
;