Mercurial > mplayer.hg
annotate stream/tvi_dshow.c @ 25068:4b14d188ed34
Add all passed to VID_SET_FORMAT formats to the end of
available format list (but report call as failed, to
continue checking formats).
This gives small chance to build graph even if device
does not report about particular format as supported.
This makes mplayer be able to work with PVR-150 card
(card's driver does not report about yuy2 format, but
accepts connection and works with it).
author | voroshil |
---|---|
date | Sun, 18 Nov 2007 13:17:00 +0000 |
parents | 5abe2c29b7d8 |
children | 82884fde28eb |
rev | line source |
---|---|
24744 | 1 /* |
2 * TV support under Win32 | |
3 * | |
4 * (C) 2007 Vladimir Voroshilov <voroshil@gmail.com>. | |
5 * | |
6 * Based on tvi_dummy.c with help of tv.c, tvi_v4l2.c code . | |
7 * | |
8 * ------------------------------------------------------------------------------- | |
9 * | |
10 * This program is free software; you can redistribute it and/or modify | |
11 * it under the terms of the GNU General Public License as published by | |
12 * the Free Software Foundation; either version 2 of the License, or | |
13 * (at your option) any later version. | |
14 * | |
15 * This program is distributed in the hope that it will be useful, | |
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
18 * GNU General Public License for more details. | |
19 * | |
20 * You should have received a copy of the GNU General Public License | |
21 * along with this program; if not, write to the Free Software | |
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | |
23 * | |
24 * | |
25 * ------------------------------------------------------------------------------- | |
26 * | |
27 * | |
28 * WARNING: This is alpha code! | |
29 * | |
30 * Abilities: | |
31 * * Watching TV under Win32 using WDM Capture driver and DirectShow | |
32 * * Grabbing synchronized audio/video with mencoder (synchronization is beeing done by DirectShow) | |
33 * * If device driver provides IAMStreamConfig interface, user can choose width/height with "-tv height=<h>:width=<w>" | |
34 * * Adjusting BRIGHTNESS,HUE,SATURATION,CONTRAST if supported by device | |
35 * * Selecting Tuner,S-Video,... as media source | |
36 * * User can select used video capture device, passing -tv device=<dev#> | |
37 * * User can select used audio input, passing -tv audioid=<input#> | |
38 * | |
39 * options which will not be implemented (probably sometime in future, if possible): | |
40 * * alsa | |
41 * * mjpeg | |
42 * * decimation=<1|2|4> | |
43 * * quality=<0\-100> | |
44 * * forceaudio | |
45 * * forcechan=<1\-2> | |
46 * * [volume|bass|treble|balance] | |
47 * | |
48 * Works with: | |
49 * - LifeView FlyTV Prime 34FM (SAA7134 based) with driver from Ivan Uskov | |
50 * Partially works with: | |
51 * - ATI 9200 VIVO based card | |
52 * - ATI AIW 7500 | |
53 * - nVidia Ti-4400 | |
54 * | |
55 * Known bugs: | |
56 * * stream goes with 24.93 FPS (NTSC), while reporting 25 FPS (PAL) ?! | |
57 * * direct set frequency call does not work ('Insufficient Buffer' error) | |
58 * * audio stream goes with about 1 sample/sec rate when capturing sound from audio card | |
59 * | |
60 * TODO: | |
61 * * check audio with small buffer on vivo !!! | |
62 * * norm for IAMVideoDecoder and for IAMTVtuner - differs !! | |
63 * * check how to change TVFormat on VIVO card without tuner | |
64 * * Flip image upside-down for RGB formats. | |
65 * * | |
66 * * remove debug sleep() | |
67 * * Add some notes to methods' parameters | |
68 * * refactor console messages | |
69 * * check using header files and keep only needed | |
70 * * add additional comments to methods' bodies | |
71 * | |
72 */ | |
73 | |
74 | |
75 /// \ingroup tvi_dshow | |
76 | |
77 #include "config.h" | |
78 | |
79 #include <stdio.h> | |
80 #include "libmpcodecs/img_format.h" | |
81 #include "libaf/af_format.h" | |
82 #include "help_mp.h" | |
83 #include "osdep/timer.h" | |
84 | |
85 | |
86 #include "tv.h" | |
87 #include "mp_msg.h" | |
88 #include "frequencies.h" | |
89 | |
90 | |
91 #include "tvi_dshow.h" | |
92 | |
93 static tvi_handle_t *tvi_init_dshow(tv_param_t* tv_param); | |
94 | |
95 /* | |
96 *--------------------------------------------------------------------------------------- | |
97 * | |
98 * Data structures | |
99 * | |
100 *--------------------------------------------------------------------------------------- | |
101 */ | |
102 /** | |
103 information about this file | |
104 */ | |
105 tvi_info_t tvi_info_dshow = { | |
106 tvi_init_dshow, | |
107 "DirectShow TV", | |
108 "dshow", | |
109 "Vladimir Voroshilov", | |
110 "Very experimental!! Use with caution" | |
111 }; | |
112 | |
113 | |
114 /** | |
115 ringbuffer related info | |
116 */ | |
117 typedef struct { | |
118 CRITICAL_SECTION *pMutex; ///< pointer to critical section (mutex) | |
119 char **ringbuffer; ///< ringbuffer array | |
120 double*dpts; ///< samples' timestamps | |
121 | |
122 int buffersize; ///< size of buffer in blocks | |
123 int blocksize; ///< size of individual block | |
124 int head; ///< index of first valid sample | |
125 int tail; ///< index of last valid sample | |
126 int count; ///< count of valid samples in ringbuffer | |
127 double tStart; ///< pts of first sample (first sample should have pts 0) | |
128 } grabber_ringbuffer_t; | |
129 | |
130 /** | |
131 CSampleGrabberCD definition | |
132 */ | |
133 typedef struct CSampleGrabberCB { | |
134 ISampleGrabberCBVtbl *lpVtbl; | |
135 int refcount; | |
136 GUID interfaces[2]; | |
137 grabber_ringbuffer_t *pbuf; | |
138 } CSampleGrabberCB; | |
139 | |
140 typedef struct { | |
141 int dev_index; ///< capture device index in device list (defaul: 0, first available device) | |
142 int adev_index; ///< audio capture device index in device list (default: -1, not used) | |
143 int immediate_mode; ///< immediate mode (no sound capture) | |
144 int state; ///< state: 1-filter graph running, 0-filter graph stopped | |
145 int direct_setfreq_call; ///< 0-find nearest channels from system channel list(workaround),1-direct call to set frequency | |
146 int direct_getfreq_call; ///< 0-find frequncy from frequency table (workaround),1-direct call to get frequency | |
147 | |
148 int fcc; ///< used video format code (FourCC) | |
149 int width; ///< picture width (default: auto) | |
150 int height; ///< picture height (default: auto) | |
151 | |
152 int channels; ///< number of audio channels (default: auto) | |
153 int samplerate; ///< audio samplerate (default: auto) | |
154 | |
155 long *freq_table; ///< frequency table (in Hz) | |
156 int freq_table_len; ///< length of freq table | |
157 int first_channel; ///< channel number of first entry in freq table | |
158 int input; ///< used input | |
159 | |
160 // video related stuff | |
161 int nVideoFormatUsed; ///< index of used video format | |
162 AM_MEDIA_TYPE **arpmtVideo; ///< available video formats | |
163 VIDEO_STREAM_CONFIG_CAPS **arVideoCaps; ///< capabilities of output video | |
164 AM_MEDIA_TYPE *pmtVideo; ///< video stream properties | |
165 grabber_ringbuffer_t *v_buf; | |
166 IBaseFilter *pVideoFilter; ///< interface for capture device | |
167 IAMStreamConfig *pVideoStreamConfig; ///< for configuring video stream | |
168 | |
169 // audio related stuff | |
170 int nAudioFormatUsed; ///< index of used audio format | |
171 AM_MEDIA_TYPE **arpmtAudio; ///< available audio formats | |
172 AUDIO_STREAM_CONFIG_CAPS **arAudioCaps; ///< capabilities of output audio | |
173 AM_MEDIA_TYPE *pmtAudio; ///< audio stream properties. | |
174 grabber_ringbuffer_t *a_buf; | |
175 IBaseFilter *pAudioFilter; ///< interface for audio capture device (if adevice passed) | |
176 IAMStreamConfig *pAudioStreamConfig; ///< for configuring audio stream | |
177 | |
178 AM_MEDIA_TYPE *pmtVBI; ///< available audio formats | |
179 grabber_ringbuffer_t *vbi_buf; | |
180 | |
181 IAMTVTuner *pTVTuner; ///< interface for tuner device | |
182 IGraphBuilder *pGraph; ///< filter graph | |
183 ICaptureGraphBuilder2 *pBuilder; ///< graph builder | |
184 IMediaControl *pMediaControl; ///< interface for controlling graph (start, stop,...) | |
185 IAMVideoProcAmp *pVideoProcAmp; ///< for adjusting hue,saturation,etc | |
186 IAMCrossbar *pCrossbar; ///< for selecting input (Tuner,Composite,S-Video,...) | |
187 DWORD dwRegister; ///< allow graphedit to connect to our graph | |
188 CSampleGrabberCB* pCSGCB; ///< callback object | |
189 void *priv_vbi; ///< private VBI data structure | |
190 tt_stream_props tsp; ///< data for VBI initialization | |
191 | |
192 tv_param_t* tv_param; ///< TV parameters | |
193 } priv_t; | |
194 | |
195 #include "tvi_def.h" | |
196 | |
197 /** | |
198 country table entry structure (for loading freq table stored in kstvtuner.ax | |
199 | |
200 \note | |
201 structure have to be 2-byte aligned and have 10-byte length!! | |
202 */ | |
203 typedef struct __attribute__((__packed__)) { | |
204 WORD CountryCode; ///< Country code | |
205 WORD CableFreqTable; ///< index of resource with frequencies for cable channels | |
206 WORD BroadcastFreqTable; ///< index of resource with frequencies for broadcast channels | |
207 DWORD VideoStandard; ///< used video standard | |
208 } TRCCountryList; | |
209 /** | |
210 information about image formats | |
211 */ | |
212 typedef struct { | |
213 uint32_t fmt; ///< FourCC | |
214 const GUID *subtype; ///< DirectShow's subtype | |
215 int nBits; ///< number of bits | |
216 int nCompression; ///< complression | |
217 int tail; ///< number of additional bytes followed VIDEOINFOHEADER structure | |
218 } img_fmt; | |
219 | |
220 /* | |
221 *--------------------------------------------------------------------------------------- | |
222 * | |
223 * Methods forward declaration | |
224 * | |
225 *--------------------------------------------------------------------------------------- | |
226 */ | |
227 static HRESULT init_ringbuffer(grabber_ringbuffer_t * rb, int buffersize, | |
228 int blocksize); | |
229 static HRESULT show_filter_info(IBaseFilter * pFilter); | |
230 #if 0 | |
231 //defined in current MinGW release | |
232 HRESULT STDCALL GetRunningObjectTable(DWORD, IRunningObjectTable **); | |
233 HRESULT STDCALL CreateItemMoniker(LPCOLESTR, LPCOLESTR, IMoniker **); | |
234 #endif | |
235 static CSampleGrabberCB *CSampleGrabberCB_Create(grabber_ringbuffer_t * | |
236 pbuf); | |
237 static int set_crossbar_input(priv_t * priv, int input); | |
238 static int subtype2imgfmt(const GUID * subtype); | |
239 | |
240 /* | |
241 *--------------------------------------------------------------------------------------- | |
242 * | |
243 * Global constants and variables | |
244 * | |
245 *--------------------------------------------------------------------------------------- | |
246 */ | |
247 /** | |
248 lookup tables for physical connector types | |
249 */ | |
250 static const struct { | |
251 long type; | |
252 char *name; | |
253 } tv_physcon_types[]={ | |
254 {PhysConn_Video_Tuner, "Tuner" }, | |
255 {PhysConn_Video_Composite, "Composite" }, | |
256 {PhysConn_Video_SVideo, "S-Video" }, | |
257 {PhysConn_Video_RGB, "RGB" }, | |
258 {PhysConn_Video_YRYBY, "YRYBY" }, | |
259 {PhysConn_Video_SerialDigital, "SerialDigital" }, | |
260 {PhysConn_Video_ParallelDigital, "ParallelDigital"}, | |
261 {PhysConn_Video_VideoDecoder, "VideoDecoder" }, | |
262 {PhysConn_Video_VideoEncoder, "VideoEncoder" }, | |
263 {PhysConn_Video_SCART, "SCART" }, | |
264 {PhysConn_Video_Black, "Blaack" }, | |
265 {PhysConn_Audio_Tuner, "Tuner" }, | |
266 {PhysConn_Audio_Line, "Line" }, | |
267 {PhysConn_Audio_Mic, "Mic" }, | |
268 {PhysConn_Audio_AESDigital, "AESDiital" }, | |
269 {PhysConn_Audio_SPDIFDigital, "SPDIFDigital" }, | |
270 {PhysConn_Audio_AudioDecoder, "AudioDecoder" }, | |
271 {PhysConn_Audio_SCSI, "SCSI" }, | |
272 {PhysConn_Video_SCSI, "SCSI" }, | |
273 {PhysConn_Audio_AUX, "AUX" }, | |
274 {PhysConn_Video_AUX, "AUX" }, | |
275 {PhysConn_Audio_1394, "1394" }, | |
276 {PhysConn_Video_1394, "1394" }, | |
277 {PhysConn_Audio_USB, "USB" }, | |
278 {PhysConn_Video_USB, "USB" }, | |
279 {-1, NULL } | |
280 }; | |
281 | |
282 static const struct { | |
283 char *chanlist_name; | |
284 int country_code; | |
285 } tv_chanlist2country[]={ | |
286 {"us-bcast", 1}, | |
287 {"russia", 7}, | |
288 {"argentina", 54}, | |
289 {"japan-bcast", 81}, | |
290 {"china-bcast", 86}, | |
291 {"southafrica", 27}, | |
292 {"australia", 61}, | |
293 {"ireland", 353}, | |
294 {"france", 33}, | |
295 {"italy", 39}, | |
296 {"newzealand", 64}, | |
297 //directshow table uses eastern europe freq table for russia | |
298 {"europe-east", 7}, | |
299 //directshow table uses western europe freq table for germany | |
300 {"europe-west", 49}, | |
301 /* cable channels */ | |
302 {"us-cable", 1}, | |
303 {"us-cable-hrc", 1}, | |
304 {"japan-cable", 81}, | |
305 //default is USA | |
306 {NULL, 1} | |
307 }; | |
308 | |
309 /** | |
310 array, contains information about various supported (i hope) image formats | |
311 */ | |
312 static const img_fmt img_fmt_list[] = { | |
25054 | 313 {IMGFMT_YUY2, &MEDIASUBTYPE_YUY2, 16, IMGFMT_YUY2, 0}, |
314 {IMGFMT_YV12, &MEDIASUBTYPE_YV12, 12, IMGFMT_YV12, 0}, | |
315 {IMGFMT_IYUV, &MEDIASUBTYPE_IYUV, 12, IMGFMT_IYUV, 0}, | |
316 {IMGFMT_I420, &MEDIASUBTYPE_I420, 12, IMGFMT_I420, 0}, | |
317 {IMGFMT_UYVY, &MEDIASUBTYPE_UYVY, 16, IMGFMT_UYVY, 0}, | |
318 {IMGFMT_YVYU, &MEDIASUBTYPE_YVYU, 16, IMGFMT_YVYU, 0}, | |
319 {IMGFMT_YVU9, &MEDIASUBTYPE_YVU9, 9, IMGFMT_YVU9, 0}, | |
320 {IMGFMT_BGR32, &MEDIASUBTYPE_RGB32, 32, 0, 0}, | |
321 {IMGFMT_BGR24, &MEDIASUBTYPE_RGB24, 24, 0, 0}, | |
322 {IMGFMT_BGR16, &MEDIASUBTYPE_RGB565, 16, 3, 12}, | |
323 {IMGFMT_BGR15, &MEDIASUBTYPE_RGB555, 16, 3, 12}, | |
324 {0, &GUID_NULL, 0, 0, 0} | |
24744 | 325 }; |
326 | |
327 #define TV_NORMS_COUNT 19 | |
328 static const struct { | |
329 long index; | |
330 char *name; | |
331 } tv_norms[TV_NORMS_COUNT] = { | |
332 { | |
333 AnalogVideo_NTSC_M, "ntsc-m"}, { | |
334 AnalogVideo_NTSC_M_J, "ntsc-mj"}, { | |
335 AnalogVideo_NTSC_433, "ntsc-433"}, { | |
336 AnalogVideo_PAL_B, "pal-b"}, { | |
337 AnalogVideo_PAL_D, "pal-d"}, { | |
338 AnalogVideo_PAL_G, "pal-g"}, { | |
339 AnalogVideo_PAL_H, "pal-h"}, { | |
340 AnalogVideo_PAL_I, "pal-i"}, { | |
341 AnalogVideo_PAL_M, "pal-m"}, { | |
342 AnalogVideo_PAL_N, "pal-n"}, { | |
343 AnalogVideo_PAL_60, "pal-60"}, { | |
344 AnalogVideo_SECAM_B, "secam-b"}, { | |
345 AnalogVideo_SECAM_D, "secam-d"}, { | |
346 AnalogVideo_SECAM_G, "secam-g"}, { | |
347 AnalogVideo_SECAM_H, "secam-h"}, { | |
348 AnalogVideo_SECAM_K, "secam-k"}, { | |
349 AnalogVideo_SECAM_K1, "secam-k1"}, { | |
350 AnalogVideo_SECAM_L, "secam-l"}, { | |
351 AnalogVideo_SECAM_L1, "secam-l1"} | |
352 }; | |
353 static long tv_available_norms[TV_NORMS_COUNT]; | |
354 static int tv_available_norms_count = 0; | |
355 | |
356 | |
357 static long *tv_available_inputs; | |
358 static int tv_available_inputs_count = 0; | |
359 | |
360 /* | |
361 *--------------------------------------------------------------------------------------- | |
362 * | |
363 * Various GUID definitions | |
364 * | |
365 *--------------------------------------------------------------------------------------- | |
366 */ | |
367 /// CLSID definitions (used for CoCreateInstance call) | |
368 DEFINE_GUID(CLSID_SampleGrabber, 0xC1F400A0, 0x3F08, 0x11d3, 0x9F, 0x0B, | |
369 0x00, 0x60, 0x08, 0x03, 0x9E, 0x37); | |
370 DEFINE_GUID(CLSID_NullRenderer, 0xC1F400A4, 0x3F08, 0x11d3, 0x9F, 0x0B, | |
371 0x00, 0x60, 0x08, 0x03, 0x9E, 0x37); | |
372 DEFINE_GUID(CLSID_SystemDeviceEnum, 0x62BE5D10, 0x60EB, 0x11d0, 0xBD, 0x3B, | |
373 0x00, 0xA0, 0xC9, 0x11, 0xCE, 0x86); | |
374 DEFINE_GUID(CLSID_CaptureGraphBuilder2, 0xBF87B6E1, 0x8C27, 0x11d0, 0xB3, | |
375 0xF0, 0x00, 0xAA, 0x00, 0x37, 0x61, 0xC5); | |
376 DEFINE_GUID(CLSID_VideoInputDeviceCategory, 0x860BB310, 0x5D01, 0x11d0, | |
377 0xBD, 0x3B, 0x00, 0xA0, 0xC9, 0x11, 0xCE, 0x86); | |
378 DEFINE_GUID(CLSID_AudioInputDeviceCategory, 0x33d9a762, 0x90c8, 0x11d0, | |
379 0xbd, 0x43, 0x00, 0xa0, 0xc9, 0x11, 0xce, 0x86); | |
380 DEFINE_GUID(CLSID_FilterGraph, 0xe436ebb3, 0x524f, 0x11ce, 0x9f, 0x53, | |
381 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70); | |
382 DEFINE_GUID(CLSID_SystemClock, 0xe436ebb1, 0x524f, 0x11ce, 0x9f, 0x53, | |
383 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70); | |
384 #ifdef NOT_USED | |
385 DEFINE_GUID(CLSID_CaptureGraphBuilder, 0xBF87B6E0, 0x8C27, 0x11d0, 0xB3, | |
386 0xF0, 0x00, 0xAA, 0x00, 0x37, 0x61, 0xC5); | |
387 DEFINE_GUID(CLSID_VideoPortManager, 0x6f26a6cd, 0x967b, 0x47fd, 0x87, 0x4a, | |
388 0x7a, 0xed, 0x2c, 0x9d, 0x25, 0xa2); | |
389 DEFINE_GUID(IID_IPin, 0x56a86891, 0x0ad4, 0x11ce, 0xb0, 0x3a, 0x00, 0x20, | |
390 0xaf, 0x0b, 0xa7, 0x70); | |
391 DEFINE_GUID(IID_ICaptureGraphBuilder, 0xbf87b6e0, 0x8c27, 0x11d0, 0xb3, | |
392 0xf0, 0x00, 0xaa, 0x00, 0x37, 0x61, 0xc5); | |
393 DEFINE_GUID(IID_IFilterGraph, 0x56a8689f, 0x0ad4, 0x11ce, 0xb0, 0x3a, 0x00, | |
394 0x20, 0xaf, 0x0b, 0xa7, 0x70); | |
395 DEFINE_GUID(PIN_CATEGORY_PREVIEW, 0xfb6c4282, 0x0353, 0x11d1, 0x90, 0x5f, | |
396 0x00, 0x00, 0xc0, 0xcc, 0x16, 0xba); | |
397 #endif | |
398 | |
399 /// IID definitions (used for QueryInterface call) | |
400 DEFINE_GUID(IID_IReferenceClock, 0x56a86897, 0x0ad4, 0x11ce, 0xb0, 0x3a, | |
401 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70); | |
402 DEFINE_GUID(IID_IAMBufferNegotiation, 0x56ED71A0, 0xAF5F, 0x11D0, 0xB3, 0xF0, | |
403 0x00, 0xAA, 0x00, 0x37, 0x61, 0xC5); | |
404 DEFINE_GUID(IID_IKsPropertySet, 0x31efac30, 0x515c, 0x11d0, 0xa9, 0xaa, | |
405 0x00, 0xaa, 0x00, 0x61, 0xbe, 0x93); | |
406 DEFINE_GUID(IID_ISampleGrabber, 0x6B652FFF, 0x11FE, 0x4fce, 0x92, 0xAD, | |
407 0x02, 0x66, 0xB5, 0xD7, 0xC7, 0x8F); | |
408 DEFINE_GUID(IID_ISampleGrabberCB, 0x0579154A, 0x2B53, 0x4994, 0xB0, 0xD0, | |
409 0xE7, 0x73, 0x14, 0x8E, 0xFF, 0x85); | |
410 DEFINE_GUID(IID_ICaptureGraphBuilder2, 0x93e5a4e0, 0x2d50, 0x11d2, 0xab, | |
411 0xfa, 0x00, 0xa0, 0xc9, 0xc6, 0xe3, 0x8d); | |
412 DEFINE_GUID(IID_ICreateDevEnum, 0x29840822, 0x5b84, 0x11d0, 0xbd, 0x3b, | |
413 0x00, 0xa0, 0xc9, 0x11, 0xce, 0x86); | |
414 DEFINE_GUID(IID_IGraphBuilder, 0x56a868a9, 0x0ad4, 0x11ce, 0xb0, 0x3a, | |
415 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70); | |
416 DEFINE_GUID(IID_IAMVideoProcAmp, 0xC6E13360, 0x30AC, 0x11d0, 0xA1, 0x8C, | |
417 0x00, 0xA0, 0xC9, 0x11, 0x89, 0x56); | |
418 DEFINE_GUID(IID_IVideoWindow, 0x56a868b4, 0x0ad4, 0x11ce, 0xb0, 0x3a, 0x00, | |
419 0x20, 0xaf, 0x0b, 0xa7, 0x70); | |
420 DEFINE_GUID(IID_IMediaControl, 0x56a868b1, 0x0ad4, 0x11ce, 0xb0, 0x3a, | |
421 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70); | |
422 DEFINE_GUID(IID_IAMTVTuner, 0x211A8766, 0x03AC, 0x11d1, 0x8D, 0x13, 0x00, | |
423 0xAA, 0x00, 0xBD, 0x83, 0x39); | |
424 DEFINE_GUID(IID_IAMCrossbar, 0xc6e13380, 0x30ac, 0x11d0, 0xa1, 0x8c, 0x00, | |
425 0xa0, 0xc9, 0x11, 0x89, 0x56); | |
426 DEFINE_GUID(IID_IAMStreamConfig, 0xc6e13340, 0x30ac, 0x11d0, 0xa1, 0x8c, | |
427 0x00, 0xa0, 0xc9, 0x11, 0x89, 0x56); | |
428 DEFINE_GUID(IID_IAMAudioInputMixer, 0x54C39221, 0x8380, 0x11d0, 0xB3, 0xF0, | |
429 0x00, 0xAA, 0x00, 0x37, 0x61, 0xC5); | |
430 DEFINE_GUID(IID_IAMTVAudio, 0x83EC1C30, 0x23D1, 0x11d1, 0x99, 0xE6, 0x00, | |
431 0xA0, 0xC9, 0x56, 0x02, 0x66); | |
432 DEFINE_GUID(IID_IAMAnalogVideoDecoder, 0xC6E13350, 0x30AC, 0x11d0, 0xA1, | |
433 0x8C, 0x00, 0xA0, 0xC9, 0x11, 0x89, 0x56); | |
434 DEFINE_GUID(IID_IPropertyBag, 0x55272a00, 0x42cb, 0x11ce, 0x81, 0x35, 0x00, | |
435 0xaa, 0x00, 0x4b, 0xb8, 0x51); | |
436 DEFINE_GUID(PIN_CATEGORY_CAPTURE, 0xfb6c4281, 0x0353, 0x11d1, 0x90, 0x5f, | |
437 0x00, 0x00, 0xc0, 0xcc, 0x16, 0xba); | |
438 DEFINE_GUID(PIN_CATEGORY_VIDEOPORT, 0xfb6c4285, 0x0353, 0x11d1, 0x90, 0x5f, | |
439 0x00, 0x00, 0xc0, 0xcc, 0x16, 0xba); | |
440 DEFINE_GUID(PIN_CATEGORY_PREVIEW, 0xfb6c4282, 0x0353, 0x11d1, 0x90, 0x5f, | |
441 0x00, 0x00, 0xc0, 0xcc, 0x16, 0xba); | |
442 DEFINE_GUID(PIN_CATEGORY_VBI, 0xfb6c4284, 0x0353, 0x11d1, 0x90, 0x5f, | |
443 0x00, 0x00, 0xc0, 0xcc, 0x16, 0xba); | |
444 DEFINE_GUID(PROPSETID_TUNER, 0x6a2e0605, 0x28e4, 0x11d0, 0xa1, 0x8c, 0x00, | |
445 0xa0, 0xc9, 0x11, 0x89, 0x56); | |
446 DEFINE_GUID(MEDIATYPE_VBI, 0xf72a76e1, 0xeb0a, 0x11d0, 0xac, 0xe4, 0x00, | |
447 0x00, 0xc0, 0xcc, 0x16, 0xba); | |
448 | |
449 #define INSTANCEDATA_OF_PROPERTY_PTR(x) (((KSPROPERTY*)(x)) + 1) | |
450 #define INSTANCEDATA_OF_PROPERTY_SIZE(x) (sizeof((x)) - sizeof(KSPROPERTY)) | |
451 | |
452 #define DEVICE_NAME_MAX_LEN 2000 | |
453 | |
454 /*--------------------------------------------------------------------------------------- | |
455 * Methods, called only from this file | |
456 *---------------------------------------------------------------------------------------*/ | |
457 | |
458 void set_buffer_preference(int nDiv,WAVEFORMATEX* pWF,IPin* pOutPin,IPin* pInPin){ | |
459 ALLOCATOR_PROPERTIES prop; | |
460 IAMBufferNegotiation* pBN; | |
461 HRESULT hr; | |
462 | |
463 prop.cbAlign = -1; | |
464 prop.cbBuffer = pWF->nAvgBytesPerSec/nDiv; | |
465 if (!prop.cbBuffer) | |
466 prop.cbBuffer = 1; | |
467 prop.cbBuffer += pWF->nBlockAlign - 1; | |
468 prop.cbBuffer -= prop.cbBuffer % pWF->nBlockAlign; | |
469 prop.cbPrefix = -1; | |
470 prop.cBuffers = -1; | |
471 | |
472 hr=OLE_QUERYINTERFACE(pOutPin,IID_IAMBufferNegotiation,pBN); | |
473 if(FAILED(hr)) | |
474 mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: pOutPin->QueryInterface(IID_IAMBufferNegotiation) Error: 0x%x\n",(unsigned int)hr); | |
475 else{ | |
476 hr=OLE_CALL_ARGS(pBN,SuggestAllocatorProperties,&prop); | |
477 if(FAILED(hr)) | |
478 mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow:pOutPin->SuggestAllocatorProperties Error:0x%x\n",(unsigned int)hr); | |
479 OLE_RELEASE_SAFE(pBN); | |
480 } | |
481 hr=OLE_QUERYINTERFACE(pInPin,IID_IAMBufferNegotiation,pBN); | |
482 if(FAILED(hr)) | |
483 mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: pInPin->QueryInterface(IID_IAMBufferNegotiation) Error: 0x%x",(unsigned int)hr); | |
484 else{ | |
485 hr=OLE_CALL_ARGS(pBN,SuggestAllocatorProperties,&prop); | |
486 if(FAILED(hr)) | |
487 mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: pInPit->SuggestAllocatorProperties Error:0x%x\n",(unsigned int)hr); | |
488 OLE_RELEASE_SAFE(pBN); | |
489 } | |
490 } | |
491 /* | |
492 *--------------------------------------------------------------------------------------- | |
493 * | |
494 * CSampleGrabberCD class. Used for receiving samples from DirectShow. | |
495 * | |
496 *--------------------------------------------------------------------------------------- | |
497 */ | |
498 /// CSampleGrabberCD destructor | |
499 static void CSampleGrabberCB_Destroy(CSampleGrabberCB * This) | |
500 { | |
501 free(This->lpVtbl); | |
502 free(This); | |
503 } | |
504 | |
505 /// CSampleGrabberCD IUnknown interface methods implementation | |
506 static long STDCALL CSampleGrabberCB_QueryInterface(ISampleGrabberCB * | |
507 This, | |
508 const GUID * riid, | |
509 void **ppvObject) | |
510 { | |
511 CSampleGrabberCB *me = (CSampleGrabberCB *) This; | |
512 GUID *r; | |
513 unsigned int i = 0; | |
514 Debug printf("CSampleGrabberCB_QueryInterface(%p) called\n", This); | |
515 if (!ppvObject) | |
516 return E_POINTER; | |
517 for (r = me->interfaces; | |
518 i < sizeof(me->interfaces) / sizeof(me->interfaces[0]); r++, i++) | |
519 if (!memcmp(r, riid, sizeof(*r))) { | |
520 OLE_CALL(This, AddRef); | |
521 *ppvObject = This; | |
522 return 0; | |
523 } | |
524 Debug printf("Query failed! (GUID: 0x%x)\n", *(unsigned int *) riid); | |
525 return E_NOINTERFACE; | |
526 } | |
527 | |
528 static long STDCALL CSampleGrabberCB_AddRef(ISampleGrabberCB * This) | |
529 { | |
530 CSampleGrabberCB *me = (CSampleGrabberCB *) This; | |
531 Debug printf("CSampleGrabberCB_AddRef(%p) called (ref:%d)\n", This, | |
532 me->refcount); | |
533 return ++(me->refcount); | |
534 } | |
535 | |
536 static long STDCALL CSampleGrabberCB_Release(ISampleGrabberCB * This) | |
537 { | |
538 CSampleGrabberCB *me = (CSampleGrabberCB *) This; | |
539 Debug printf("CSampleGrabberCB_Release(%p) called (new ref:%d)\n", | |
540 This, me->refcount - 1); | |
541 if (--(me->refcount) == 0) | |
542 CSampleGrabberCB_Destroy(me); | |
543 return 0; | |
544 } | |
545 | |
546 | |
547 HRESULT STDCALL CSampleGrabberCB_BufferCB(ISampleGrabberCB * This, | |
548 double SampleTime, | |
549 BYTE * pBuffer, long lBufferLen) | |
550 { | |
551 CSampleGrabberCB *this = (CSampleGrabberCB *) This; | |
552 grabber_ringbuffer_t *rb = this->pbuf; | |
553 | |
554 if (!lBufferLen) | |
555 return E_FAIL; | |
556 | |
557 if (!rb->ringbuffer) { | |
558 rb->buffersize /= lBufferLen; | |
559 if (init_ringbuffer(rb, rb->buffersize, lBufferLen) != S_OK) | |
560 return E_FAIL; | |
561 } | |
562 mp_msg(MSGT_TV, MSGL_DBG4, | |
563 "tvi_dshow: BufferCB(%p): len=%ld ts=%f\n", This, lBufferLen, SampleTime); | |
564 EnterCriticalSection(rb->pMutex); | |
565 if (rb->count >= rb->buffersize) { | |
566 rb->head = (rb->head + 1) % rb->buffersize; | |
567 rb->count--; | |
568 } | |
569 | |
570 memcpy(rb->ringbuffer[rb->tail], pBuffer, | |
571 lBufferLen < rb->blocksize ? lBufferLen : rb->blocksize); | |
572 rb->dpts[rb->tail] = SampleTime; | |
573 rb->tail = (rb->tail + 1) % rb->buffersize; | |
574 rb->count++; | |
575 LeaveCriticalSection(rb->pMutex); | |
576 | |
577 return S_OK; | |
578 } | |
579 | |
580 /// wrapper. directshow does the same when BufferCB callback is requested | |
581 HRESULT STDCALL CSampleGrabberCB_SampleCB(ISampleGrabberCB * This, | |
582 double SampleTime, | |
583 LPMEDIASAMPLE pSample) | |
584 { | |
585 char* buf; | |
586 long len; | |
587 long long tStart,tEnd; | |
588 HRESULT hr; | |
589 grabber_ringbuffer_t *rb = ((CSampleGrabberCB*)This)->pbuf; | |
590 | |
591 len=OLE_CALL(pSample,GetSize); | |
592 tStart=tEnd=0; | |
593 hr=OLE_CALL_ARGS(pSample,GetTime,&tStart,&tEnd); | |
594 if(FAILED(hr)){ | |
595 return hr; | |
596 } | |
597 mp_msg(MSGT_TV, MSGL_DBG4,"tvi_dshow: SampleCB(%p): %d/%d %f\n", This,rb->count,rb->buffersize,1e-7*tStart); | |
598 hr=OLE_CALL_ARGS(pSample,GetPointer,(void*)&buf); | |
599 if(FAILED(hr)){ | |
600 return hr; | |
601 } | |
602 hr=CSampleGrabberCB_BufferCB(This,1e-7*tStart,buf,len); | |
603 return hr; | |
604 | |
605 } | |
606 | |
607 /// main grabbing routine | |
608 static CSampleGrabberCB *CSampleGrabberCB_Create(grabber_ringbuffer_t * | |
609 pbuf) | |
610 { | |
611 CSampleGrabberCB *This = malloc(sizeof(CSampleGrabberCB)); | |
612 if (!This) | |
613 return NULL; | |
614 | |
615 This->lpVtbl = malloc(sizeof(ISampleGrabberVtbl)); | |
616 if (!This->lpVtbl) { | |
617 CSampleGrabberCB_Destroy(This); | |
618 return NULL; | |
619 } | |
620 This->refcount = 1; | |
621 This->lpVtbl->QueryInterface = CSampleGrabberCB_QueryInterface; | |
622 This->lpVtbl->AddRef = CSampleGrabberCB_AddRef; | |
623 This->lpVtbl->Release = CSampleGrabberCB_Release; | |
624 This->lpVtbl->SampleCB = CSampleGrabberCB_SampleCB; | |
625 This->lpVtbl->BufferCB = CSampleGrabberCB_BufferCB; | |
626 | |
627 This->interfaces[0] = IID_IUnknown; | |
628 This->interfaces[1] = IID_ISampleGrabberCB; | |
629 | |
630 This->pbuf = pbuf; | |
631 | |
632 return This; | |
633 } | |
634 | |
635 /* | |
636 *--------------------------------------------------------------------------------------- | |
637 * | |
638 * ROT related methods (register, unregister) | |
639 * | |
640 *--------------------------------------------------------------------------------------- | |
641 */ | |
642 /** | |
643 Registering graph in ROT. User will be able to connect to graph from GraphEdit. | |
644 */ | |
645 static HRESULT AddToRot(IUnknown * pUnkGraph, DWORD * pdwRegister) | |
646 { | |
647 IMoniker *pMoniker; | |
648 IRunningObjectTable *pROT; | |
649 WCHAR wsz[256]; | |
650 HRESULT hr; | |
651 | |
652 if (FAILED(GetRunningObjectTable(0, &pROT))) { | |
653 return E_FAIL; | |
654 } | |
655 wsprintfW(wsz, L"FilterGraph %08x pid %08x", (DWORD_PTR) pUnkGraph, | |
656 GetCurrentProcessId()); | |
657 hr = CreateItemMoniker(L"!", wsz, &pMoniker); | |
658 if (SUCCEEDED(hr)) { | |
659 hr = OLE_CALL_ARGS(pROT, Register, ROTFLAGS_REGISTRATIONKEEPSALIVE, | |
660 pUnkGraph, pMoniker, pdwRegister); | |
661 OLE_RELEASE_SAFE(pMoniker); | |
662 } | |
663 OLE_RELEASE_SAFE(pROT); | |
664 return hr; | |
665 } | |
666 | |
667 /// Unregistering graph in ROT | |
668 static void RemoveFromRot(DWORD dwRegister) | |
669 { | |
670 IRunningObjectTable *pROT; | |
671 if (SUCCEEDED(GetRunningObjectTable(0, &pROT))) { | |
672 OLE_CALL_ARGS(pROT, Revoke, dwRegister); | |
673 OLE_RELEASE_SAFE(pROT); | |
674 } | |
675 } | |
676 | |
677 /* | |
678 *--------------------------------------------------------------------------------------- | |
679 * | |
680 * ringbuffer related methods (init, destroy) | |
681 * | |
682 *--------------------------------------------------------------------------------------- | |
683 */ | |
684 /** | |
685 * \brief ringbuffer destroying routine | |
686 * | |
687 * \param rb pointer to empty (just allocated) ringbuffer structure | |
688 * | |
689 * \note routine does not frees memory, allocated for grabber_rinbuffer_s structure | |
690 */ | |
691 static void destroy_ringbuffer(grabber_ringbuffer_t * rb) | |
692 { | |
693 int i; | |
694 | |
695 if (!rb) | |
696 return; | |
697 | |
698 if (rb->ringbuffer) { | |
699 for (i = 0; i < rb->buffersize; i++) | |
700 if (rb->ringbuffer[i]) | |
701 free(rb->ringbuffer[i]); | |
702 free(rb->ringbuffer); | |
703 rb->ringbuffer = NULL; | |
704 } | |
705 if (rb->dpts) { | |
706 free(rb->dpts); | |
707 rb->dpts = NULL; | |
708 } | |
709 if (rb->pMutex) { | |
710 DeleteCriticalSection(rb->pMutex); | |
711 free(rb->pMutex); | |
712 rb->pMutex = NULL; | |
713 } | |
714 | |
715 rb->blocksize = 0; | |
716 rb->buffersize = 0; | |
717 rb->head = 0; | |
718 rb->tail = 0; | |
719 rb->count = 0; | |
720 } | |
721 | |
722 /** | |
723 * \brief ringbuffer initialization | |
724 * | |
725 * \param rb pointer to empty (just allocated) ringbuffer structure | |
726 * \param buffersize size of buffer in blocks | |
727 * \param blocksize size of buffer's block | |
728 * | |
729 * \return S_OK if success | |
730 * \return E_OUTOFMEMORY not enough memory | |
731 * | |
732 * \note routine does not allocates memory for grabber_rinbuffer_s structure | |
733 */ | |
734 static HRESULT init_ringbuffer(grabber_ringbuffer_t * rb, int buffersize, | |
735 int blocksize) | |
736 { | |
737 int i; | |
738 | |
739 if (!rb) | |
740 return E_OUTOFMEMORY; | |
741 | |
742 rb->buffersize = buffersize < 2 ? 2 : buffersize; | |
743 rb->blocksize = blocksize; | |
744 | |
745 mp_msg(MSGT_TV, MSGL_DBG2, "tvi_dshow: Capture buffer: %d blocks of %d bytes.\n", | |
746 rb->buffersize, rb->blocksize); | |
747 | |
748 rb->ringbuffer = (char **) malloc(rb->buffersize * sizeof(char *)); | |
749 if (!rb) | |
750 return E_POINTER; | |
751 memset(rb->ringbuffer, 0, rb->buffersize * sizeof(char *)); | |
752 | |
753 for (i = 0; i < rb->buffersize; i++) { | |
754 rb->ringbuffer[i] = (char *) malloc(rb->blocksize * sizeof(char)); | |
755 if (!rb->ringbuffer[i]) { | |
756 destroy_ringbuffer(rb); | |
757 return E_OUTOFMEMORY; | |
758 } | |
759 } | |
760 rb->dpts = (double*) malloc(rb->buffersize * sizeof(double)); | |
761 if (!rb->dpts) { | |
762 destroy_ringbuffer(rb); | |
763 return E_OUTOFMEMORY; | |
764 } | |
765 rb->head = 0; | |
766 rb->tail = 0; | |
767 rb->count = 0; | |
768 rb->tStart = -1; | |
769 rb->pMutex = (CRITICAL_SECTION *) malloc(sizeof(CRITICAL_SECTION)); | |
770 if (!rb->pMutex) { | |
771 destroy_ringbuffer(rb); | |
772 return E_OUTOFMEMORY; | |
773 } | |
774 InitializeCriticalSection(rb->pMutex); | |
775 return S_OK; | |
776 } | |
777 | |
778 /* | |
779 *--------------------------------------------------------------------------------------- | |
780 * | |
781 * Tuner related methods (frequency, capabilities, etc | |
782 * | |
783 *--------------------------------------------------------------------------------------- | |
784 */ | |
785 /** | |
786 * \brief returns string with name for givend PsysCon_* constant | |
787 * | |
788 * \param lPhysicalType constant from PhysicalConnectorType enumeration | |
789 * | |
790 * \return pointer to string with apropriate name | |
791 * | |
792 * \note | |
793 * Caller should not free returned pointer | |
794 */ | |
795 static char *physcon2str(const long lPhysicalType) | |
796 { | |
797 int i; | |
798 for(i=0; tv_physcon_types[i].name; i++) | |
799 if(tv_physcon_types[i].type==lPhysicalType) | |
800 return tv_physcon_types[i].name; | |
801 return "Unknown"; | |
802 }; | |
803 | |
804 /** | |
805 * \brief converts MPlayer's chanlist to system country code. | |
806 * | |
807 * \param chanlist MPlayer's chanlist name | |
808 * | |
809 * \return system country code | |
810 * | |
811 * \remarks | |
812 * After call to IAMTVTuner::put_CountryCode with returned value tuner switches to frequency table used in specified | |
813 * country (which is usually larger then MPlayer's one, so workaround will work fine). | |
814 * | |
815 * \todo | |
816 * Resolve trouble with cable channels (DirectShow's tuners must be switched between broadcast and cable channels modes. | |
817 */ | |
818 static int chanlist2country(char *chanlist) | |
819 { | |
820 int i; | |
821 for(i=0; tv_chanlist2country[i].chanlist_name; i++) | |
822 if (!strcmp(chanlist, tv_chanlist2country[i].chanlist_name)) | |
823 break; | |
824 return tv_chanlist2country[i].country_code; | |
825 } | |
826 | |
827 /** | |
828 * \brief loads specified resource from module and return pointer to it | |
829 * | |
830 * \param hDLL valid module desriptor | |
831 * \param index index of resource. resource with name "#<index>" will be loaded | |
832 * | |
833 * \return pointer to loader resource or NULL if error occured | |
834 */ | |
835 static void *GetRC(HMODULE hDLL, int index) | |
836 { | |
837 char szRCDATA[10]; | |
838 char szName[10]; | |
839 HRSRC hRes; | |
840 HGLOBAL hTable; | |
841 | |
842 snprintf(szRCDATA, 10, "#%d", (int)RT_RCDATA); | |
843 snprintf(szName, 10, "#%d", index); | |
844 | |
845 hRes = FindResource(hDLL, szName, szRCDATA); | |
846 if (!hRes) { | |
847 return NULL; | |
848 } | |
849 hTable = LoadResource(hDLL, hRes); | |
850 if (!hTable) { | |
851 return NULL; | |
852 } | |
853 return LockResource(hTable); | |
854 } | |
855 | |
856 /** | |
857 * \brief loads frequency table for given country from kstvtune.ax | |
858 * | |
859 * \param[in] nCountry - country code | |
860 * \param[in] nInputType (TunerInputCable or TunerInputAntenna) | |
861 * \param[out] pplFreqTable - address of variable that receives pointer to array, containing frequencies | |
862 * \param[out] pnLen length of array | |
863 * \param[out] pnFirst - channel number of first entry in array (nChannelMax) | |
864 * | |
865 * \return S_OK if success | |
866 * \return E_POINTER pplFreqTable==NULL || plFirst==NULL || pnLen==NULL | |
867 * \return E_FAIL error occured during load | |
868 * | |
869 * \remarks | |
870 * - array must be freed by caller | |
871 * - MSDN says that it is not neccessery to unlock or free resource. It will be done after unloading DLL | |
872 */ | |
873 static HRESULT load_freq_table(int nCountry, int nInputType, | |
874 long **pplFreqTable, int *pnLen, | |
875 int *pnFirst) | |
876 { | |
877 HMODULE hDLL; | |
878 long *plFreqTable; | |
879 TRCCountryList *pCountryList; | |
880 int i, index; | |
881 | |
882 mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: load_freq_table called %d (%d)\n",nCountry,nInputType); | |
883 /* ASSERT(sizeof(TRCCountryList)==10); // need properly aligned structure */ | |
884 | |
885 if (!pplFreqTable || !pnFirst || !pnLen) | |
886 return E_POINTER; | |
887 if (!nCountry) | |
888 return E_FAIL; | |
889 | |
890 hDLL = LoadLibrary("kstvtune.ax"); | |
891 if (!hDLL) { | |
892 return E_FAIL; | |
893 } | |
894 pCountryList = GetRC(hDLL, 9999); | |
895 if (!pCountryList) { | |
896 FreeLibrary(hDLL); | |
897 return E_FAIL; | |
898 } | |
899 for (i = 0; pCountryList[i].CountryCode != 0; i++) | |
900 if (pCountryList[i].CountryCode == nCountry) | |
901 break; | |
902 if (pCountryList[i].CountryCode == 0) { | |
903 FreeLibrary(hDLL); | |
904 return E_FAIL; | |
905 } | |
906 if (nInputType == TunerInputCable) | |
907 index = pCountryList[i].CableFreqTable; | |
908 else | |
909 index = pCountryList[i].BroadcastFreqTable; | |
910 | |
911 plFreqTable = GetRC(hDLL, index); //First element is number of first channel, second - number of last channel | |
912 if (!plFreqTable) { | |
913 FreeLibrary(hDLL); | |
914 return E_FAIL; | |
915 } | |
916 *pnFirst = plFreqTable[0]; | |
917 *pnLen = (int) (plFreqTable[1] - plFreqTable[0] + 1); | |
918 *pplFreqTable = (long *) malloc((*pnLen) * sizeof(long)); | |
919 if (!*pplFreqTable) { | |
920 FreeLibrary(hDLL); | |
921 return E_FAIL; | |
922 } | |
923 for (i = 0; i < *pnLen; i++) { | |
924 (*pplFreqTable)[i] = plFreqTable[i + 2]; | |
925 } | |
926 FreeLibrary(hDLL); | |
927 return S_OK; | |
928 } | |
929 | |
930 /** | |
931 * \brief tunes to given frequency through IKsPropertySet call | |
932 * | |
933 * \param pTVTuner IAMTVTuner interface of capture device | |
934 * \param lFreq frequency to tune (in Hz) | |
935 * | |
936 * \return S_OK success | |
937 * \return apropriate error code otherwise | |
938 * | |
939 * \note | |
940 * Due to either bug in driver or error in following code calll to IKsProperty::Set | |
941 * in this methods always fail with error 0x8007007a. | |
942 * | |
943 * \todo test code on other machines and an error | |
944 */ | |
945 static HRESULT set_frequency_direct(IAMTVTuner * pTVTuner, long lFreq) | |
946 { | |
947 HRESULT hr; | |
948 DWORD dwSupported = 0; | |
949 DWORD cbBytes = 0; | |
950 KSPROPERTY_TUNER_MODE_CAPS_S mode_caps; | |
951 KSPROPERTY_TUNER_FREQUENCY_S frequency; | |
952 IKsPropertySet *pKSProp; | |
953 | |
954 mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: set_frequency_direct called\n"); | |
955 | |
956 memset(&mode_caps, 0, sizeof(mode_caps)); | |
957 memset(&frequency, 0, sizeof(frequency)); | |
958 | |
959 hr = OLE_QUERYINTERFACE(pTVTuner, IID_IKsPropertySet, pKSProp); | |
960 if (FAILED(hr)) | |
961 return hr; //no IKsPropertySet interface | |
962 | |
963 mode_caps.Mode = AMTUNER_MODE_TV; | |
964 hr = OLE_CALL_ARGS(pKSProp, QuerySupported, &PROPSETID_TUNER, | |
965 KSPROPERTY_TUNER_MODE_CAPS, &dwSupported); | |
966 if (FAILED(hr)) { | |
967 OLE_RELEASE_SAFE(pKSProp); | |
968 return hr; | |
969 } | |
970 | |
971 if (!dwSupported & KSPROPERTY_SUPPORT_GET) { | |
972 OLE_RELEASE_SAFE(pKSProp); | |
973 return E_FAIL; //PROPSETID_TINER not supported | |
974 } | |
975 | |
976 hr = OLE_CALL_ARGS(pKSProp, Get, &PROPSETID_TUNER, | |
977 KSPROPERTY_TUNER_MODE_CAPS, | |
978 INSTANCEDATA_OF_PROPERTY_PTR(&mode_caps), | |
979 INSTANCEDATA_OF_PROPERTY_SIZE(mode_caps), | |
980 &mode_caps, sizeof(mode_caps), &cbBytes); | |
981 | |
982 frequency.Frequency = lFreq; | |
983 | |
984 if (mode_caps.Strategy == KS_TUNER_STRATEGY_DRIVER_TUNES) | |
985 frequency.TuningFlags = KS_TUNER_TUNING_FINE; | |
986 else | |
987 frequency.TuningFlags = KS_TUNER_TUNING_EXACT; | |
988 | |
989 if (lFreq < mode_caps.MinFrequency || lFreq > mode_caps.MaxFrequency) { | |
990 OLE_RELEASE_SAFE(pKSProp); | |
991 return E_FAIL; | |
992 } | |
993 | |
994 hr = OLE_CALL_ARGS(pKSProp, Set, &PROPSETID_TUNER, | |
995 KSPROPERTY_TUNER_FREQUENCY, | |
996 INSTANCEDATA_OF_PROPERTY_PTR(&frequency), | |
997 INSTANCEDATA_OF_PROPERTY_SIZE(frequency), | |
998 &frequency, sizeof(frequency)); | |
999 if (FAILED(hr)) { | |
1000 OLE_RELEASE_SAFE(pKSProp); | |
1001 return hr; | |
1002 } | |
1003 | |
1004 OLE_RELEASE_SAFE(pKSProp); | |
1005 | |
1006 return S_OK; | |
1007 } | |
1008 | |
1009 /** | |
1010 * \brief find channel with nearest frequency and set it | |
1011 * | |
1012 * \param priv driver's private data | |
1013 * \param lFreq frequency in Hz | |
1014 * | |
1015 * \return S_OK if success | |
1016 * \return E_FAIL if error occured | |
1017 */ | |
1018 static HRESULT set_nearest_freq(priv_t * priv, long lFreq) | |
1019 { | |
1020 HRESULT hr; | |
1021 int i; | |
1022 long lFreqDiff=-1; | |
1023 int nChannel; | |
1024 TunerInputType tunerInput; | |
1025 long lInput; | |
1026 | |
1027 mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: set_nearest_freq called\n"); | |
1028 if(priv->freq_table_len == -1 && !priv->freq_table) { | |
1029 | |
1030 hr = OLE_CALL_ARGS(priv->pTVTuner, get_ConnectInput, &lInput); | |
1031 if(FAILED(hr)){ //Falling back to 0 | |
1032 lInput=0; | |
1033 } | |
1034 | |
1035 hr = OLE_CALL_ARGS(priv->pTVTuner, get_InputType, lInput, &tunerInput); | |
1036 | |
1037 if (load_freq_table(chanlist2country(priv->tv_param->chanlist), tunerInput, &(priv->freq_table), &(priv->freq_table_len), &(priv->first_channel)) != S_OK) {//FIXME | |
1038 priv->freq_table_len=0; | |
1039 priv->freq_table=NULL; | |
1040 mp_msg(MSGT_TV, MSGL_ERR, MSGTR_TVI_DS_UnableExtractFreqTable); | |
1041 return E_FAIL; | |
1042 }; | |
1043 mp_msg(MSGT_TV, MSGL_V, MSGTR_TVI_DS_FreqTableLoaded, tunerInput == TunerInputAntenna ? "broadcast" : "cable", | |
1044 chanlist2country(priv->tv_param->chanlist), priv->freq_table_len); | |
1045 } | |
1046 | |
1047 if (priv->freq_table_len <= 0) | |
1048 return E_FAIL; | |
1049 | |
1050 //FIXME: rewrite search algo | |
1051 nChannel = -1; | |
1052 for (i = 0; i < priv->freq_table_len; i++) { | |
1053 if (nChannel == -1 || labs(lFreq - priv->freq_table[i]) < lFreqDiff) { | |
1054 nChannel = priv->first_channel + i; | |
1055 lFreqDiff = labs(lFreq - priv->freq_table[i]); | |
1056 } | |
1057 } | |
1058 if (nChannel == -1) { | |
1059 mp_msg(MSGT_TV,MSGL_ERR, MSGTR_TVI_DS_UnableFindNearestChannel); | |
1060 return E_FAIL; | |
1061 } | |
1062 hr = OLE_CALL_ARGS(priv->pTVTuner, put_Channel, nChannel, | |
1063 AMTUNER_SUBCHAN_DEFAULT, AMTUNER_SUBCHAN_DEFAULT); | |
1064 if (FAILED(hr)) { | |
1065 mp_msg(MSGT_TV,MSGL_ERR,MSGTR_TVI_DS_UnableToSetChannel, (unsigned int)hr); | |
1066 return E_FAIL; | |
1067 } | |
1068 return S_OK; | |
1069 } | |
1070 | |
1071 /** | |
1072 * \brief setting frequency. decides whether use direct call/workaround | |
1073 * | |
1074 * \param priv driver's private data | |
1075 * \param lFreq frequency in Hz | |
1076 * | |
1077 * \return TVI_CONTROL_TRUE if success | |
1078 * \return TVI_CONTROL_FALSE if error occured | |
1079 * | |
1080 * \todo check for freq boundary | |
1081 */ | |
1082 static int set_frequency(priv_t * priv, long lFreq) | |
1083 { | |
1084 HRESULT hr; | |
1085 | |
1086 mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: set_frequency called\n"); | |
1087 if (!priv->pTVTuner) | |
1088 return TVI_CONTROL_FALSE; | |
1089 if (priv->direct_setfreq_call) { //using direct call to set frequency | |
1090 hr = set_frequency_direct(priv->pTVTuner, lFreq); | |
1091 if (FAILED(hr)) { | |
1092 mp_msg(MSGT_TV, MSGL_V, MSGTR_TVI_DS_DirectSetFreqFailed); | |
1093 priv->direct_setfreq_call = 0; | |
1094 } | |
1095 } | |
1096 if (!priv->direct_setfreq_call) { | |
1097 hr = set_nearest_freq(priv, lFreq); | |
1098 } | |
1099 if (FAILED(hr)) | |
1100 return TVI_CONTROL_FALSE; | |
1101 #ifdef DEPRECATED | |
1102 priv->pGrabber->ClearBuffer(priv->pGrabber); | |
1103 #endif | |
1104 return TVI_CONTROL_TRUE; | |
1105 } | |
1106 | |
1107 /** | |
1108 * \brief return current frequency from tuner (in Hz) | |
1109 * | |
1110 * \param pTVTuner IAMTVTuner interface of tuner | |
1111 * \param plFreq address of variable that receives current frequency | |
1112 * | |
1113 * \return S_OK success | |
1114 * \return E_POINTER pTVTuner==NULL || plFreq==NULL | |
1115 * \return apropriate error code otherwise | |
1116 */ | |
1117 static HRESULT get_frequency_direct(IAMTVTuner * pTVTuner, long *plFreq) | |
1118 { | |
1119 HRESULT hr; | |
1120 KSPROPERTY_TUNER_STATUS_S TunerStatus; | |
1121 DWORD cbBytes; | |
1122 IKsPropertySet *pKSProp; | |
1123 mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: get_frequency_direct called\n"); | |
1124 | |
1125 if (!plFreq) | |
1126 return E_POINTER; | |
1127 | |
1128 hr = OLE_QUERYINTERFACE(pTVTuner, IID_IKsPropertySet, pKSProp); | |
1129 if (FAILED(hr)) { | |
1130 mp_msg(MSGT_TV, MSGL_DBG2, "tvi_dshow: Get freq QueryInterface failed\n"); | |
1131 return hr; | |
1132 } | |
1133 | |
1134 hr = OLE_CALL_ARGS(pKSProp, Get, &PROPSETID_TUNER, | |
1135 KSPROPERTY_TUNER_STATUS, | |
1136 INSTANCEDATA_OF_PROPERTY_PTR(&TunerStatus), | |
1137 INSTANCEDATA_OF_PROPERTY_SIZE(TunerStatus), | |
1138 &TunerStatus, sizeof(TunerStatus), &cbBytes); | |
1139 if (FAILED(hr)) { | |
1140 mp_msg(MSGT_TV, MSGL_DBG2, "tvi_dshow: Get freq Get failure\n"); | |
1141 return hr; | |
1142 } | |
1143 *plFreq = TunerStatus.CurrentFrequency; | |
1144 return S_OK; | |
1145 } | |
1146 | |
1147 /** | |
1148 * \brief gets current frequency | |
1149 * | |
1150 * \param priv driver's private data structure | |
1151 * \param plFreq - pointer to long int to store frequency to (in Hz) | |
1152 * | |
1153 * \return TVI_CONTROL_TRUE if success, TVI_CONTROL_FALSE otherwise | |
1154 */ | |
1155 static int get_frequency(priv_t * priv, long *plFreq) | |
1156 { | |
1157 HRESULT hr; | |
1158 | |
1159 mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: get_frequency called\n"); | |
1160 | |
1161 if (!plFreq || !priv->pTVTuner) | |
1162 return TVI_CONTROL_FALSE; | |
1163 | |
1164 if (priv->direct_getfreq_call) { //using direct call to get frequency | |
1165 hr = get_frequency_direct(priv->pTVTuner, plFreq); | |
1166 if (FAILED(hr)) { | |
1167 mp_msg(MSGT_TV, MSGL_INFO, MSGTR_TVI_DS_DirectGetFreqFailed); | |
1168 priv->direct_getfreq_call = 0; | |
1169 } | |
1170 } | |
1171 if (!priv->direct_getfreq_call) { | |
1172 hr=OLE_CALL_ARGS(priv->pTVTuner, get_VideoFrequency, plFreq); | |
1173 if (FAILED(hr)) | |
1174 return TVI_CONTROL_FALSE; | |
1175 | |
1176 } | |
1177 return TVI_CONTROL_TRUE; | |
1178 } | |
1179 | |
1180 /** | |
1181 * \brief get tuner capabilities | |
1182 * | |
1183 * \param priv driver's private data | |
1184 */ | |
1185 static void get_capabilities(priv_t * priv) | |
1186 { | |
1187 long lAvailableFormats; | |
1188 HRESULT hr; | |
1189 int i; | |
1190 long lInputPins, lOutputPins, lRelated, lPhysicalType; | |
1191 IEnumPins *pEnum; | |
1192 char tmp[200]; | |
1193 IPin *pPin = 0; | |
1194 PIN_DIRECTION ThisPinDir; | |
1195 PIN_INFO pi; | |
1196 IAMAudioInputMixer *pIAMixer; | |
1197 | |
1198 mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: get_capabilities called\n"); | |
1199 if (priv->pTVTuner) { | |
1200 | |
1201 mp_msg(MSGT_TV, MSGL_V, MSGTR_TVI_DS_SupportedNorms); | |
1202 hr = OLE_CALL_ARGS(priv->pTVTuner, get_AvailableTVFormats, | |
1203 &lAvailableFormats); | |
1204 if (FAILED(hr)) | |
1205 tv_available_norms_count = 0; | |
1206 else { | |
1207 for (i = 0; i < TV_NORMS_COUNT; i++) { | |
1208 if (lAvailableFormats & tv_norms[i].index) { | |
1209 tv_available_norms[tv_available_norms_count] = i; | |
1210 mp_msg(MSGT_TV, MSGL_V, " %d=%s;", | |
1211 tv_available_norms_count + 1, tv_norms[i].name); | |
1212 tv_available_norms_count++; | |
1213 } | |
1214 } | |
1215 } | |
1216 mp_msg(MSGT_TV, MSGL_INFO, "\n"); | |
1217 } | |
1218 if (priv->pCrossbar) { | |
1219 OLE_CALL_ARGS(priv->pCrossbar, get_PinCounts, &lOutputPins, | |
1220 &lInputPins); | |
1221 | |
1222 tv_available_inputs = (long *) malloc(sizeof(long) * lInputPins); | |
1223 tv_available_inputs_count = 0; | |
1224 | |
1225 mp_msg(MSGT_TV, MSGL_V, MSGTR_TVI_DS_AvailableVideoInputs); | |
1226 for (i = 0; i < lInputPins; i++) { | |
1227 OLE_CALL_ARGS(priv->pCrossbar, get_CrossbarPinInfo, 1, i, | |
1228 &lRelated, &lPhysicalType); | |
1229 | |
1230 if (lPhysicalType < 0x1000) { | |
1231 tv_available_inputs[tv_available_inputs_count++] = i; | |
1232 mp_msg(MSGT_TV, MSGL_V, " %d=%s;", | |
1233 tv_available_inputs_count - 1, | |
1234 physcon2str(lPhysicalType)); | |
1235 } | |
1236 } | |
1237 mp_msg(MSGT_TV, MSGL_INFO, "\n"); | |
1238 | |
1239 set_crossbar_input(priv, 0); | |
1240 } | |
1241 | |
1242 if (priv->adev_index != -1) { | |
1243 hr = OLE_CALL_ARGS(priv->pAudioFilter, EnumPins, &pEnum); | |
1244 if (FAILED(hr)) | |
1245 return; | |
1246 mp_msg(MSGT_TV, MSGL_V, MSGTR_TVI_DS_AvailableAudioInputs); | |
1247 i = 0; | |
1248 while (OLE_CALL_ARGS(pEnum, Next, 1, &pPin, NULL) == S_OK) { | |
1249 memset(&pi, 0, sizeof(pi)); | |
1250 memset(tmp, 0, 200); | |
1251 OLE_CALL_ARGS(pPin, QueryDirection, &ThisPinDir); | |
1252 if (ThisPinDir == PINDIR_INPUT) { | |
1253 OLE_CALL_ARGS(pPin, QueryPinInfo, &pi); | |
1254 wtoa(pi.achName, tmp, 200); | |
1255 OLE_RELEASE_SAFE(pi.pFilter); | |
1256 mp_msg(MSGT_TV, MSGL_V, " %d=%s", i, tmp); | |
1257 mp_msg(MSGT_TV, MSGL_DBG3, " (%p)", pPin); | |
1258 hr = OLE_QUERYINTERFACE(pPin, IID_IAMAudioInputMixer,pIAMixer); | |
1259 if (SUCCEEDED(hr)) { | |
1260 if (i == priv->tv_param->audio_id) { | |
1261 OLE_CALL_ARGS(pIAMixer, put_Enable, TRUE); | |
1262 if(priv->tv_param->volume>0) | |
1263 OLE_CALL_ARGS(pIAMixer, put_MixLevel, 0.01 * priv->tv_param->volume); | |
1264 #if 0 | |
1265 else | |
1266 OLE_CALL_ARGS(pIAMixer, put_MixLevel, 1.0); | |
1267 #endif | |
1268 mp_msg(MSGT_TV, MSGL_V, MSGTR_TVI_DS_InputSelected); | |
1269 } else { | |
1270 OLE_CALL_ARGS(pIAMixer, put_Enable, FALSE); | |
1271 #if 0 | |
1272 OLE_CALL_ARGS(pIAMixer, put_MixLevel, 0.0); | |
1273 #endif | |
1274 } | |
1275 OLE_RELEASE_SAFE(pIAMixer); | |
1276 } | |
1277 mp_msg(MSGT_TV, MSGL_V, ";"); | |
1278 OLE_RELEASE_SAFE(pPin); | |
1279 i++; | |
1280 } | |
1281 } | |
1282 mp_msg(MSGT_TV, MSGL_INFO, "\n"); | |
1283 OLE_RELEASE_SAFE(pEnum); | |
1284 } | |
1285 } | |
1286 | |
1287 /* | |
1288 *--------------------------------------------------------------------------------------- | |
1289 * | |
1290 * Filter related methods | |
1291 * | |
1292 *--------------------------------------------------------------------------------------- | |
1293 */ | |
1294 /** | |
1295 * \brief building in graph audio/video capture chain | |
1296 * | |
1297 * \param priv driver's private data | |
1298 * \param pCaptureFilter pointer to capture device's IBaseFilter interface | |
1299 * \param pbuf ringbuffer data structure | |
1300 * \param pmt media type for chain (AM_MEDIA_TYPE) | |
1301 * | |
1302 * \note routine does not frees memory, allocated for grabber_rinbuffer_s structure | |
1303 */ | |
1304 static HRESULT build_sub_graph(priv_t * priv, IBaseFilter * pCaptureFilter, | |
1305 grabber_ringbuffer_t * pbuf, | |
25063
29260745e4fa
Pass all available formats to chain building routine and
voroshil
parents:
25061
diff
changeset
|
1306 AM_MEDIA_TYPE ** arpmt, |
29260745e4fa
Pass all available formats to chain building routine and
voroshil
parents:
25061
diff
changeset
|
1307 AM_MEDIA_TYPE* pmt, const GUID* ppin_category) |
24744 | 1308 { |
1309 HRESULT hr; | |
25063
29260745e4fa
Pass all available formats to chain building routine and
voroshil
parents:
25061
diff
changeset
|
1310 int nFormatProbed = 0; |
25029
c9f20e41bc13
Make sure that mplayer will receive actual media type
voroshil
parents:
25028
diff
changeset
|
1311 |
24744 | 1312 IPin *pSGIn; |
1313 IPin *pSGOut; | |
1314 IPin *pNRIn=NULL; | |
1315 IPin *pCapturePin; | |
1316 | |
1317 IBaseFilter *pNR = NULL; | |
1318 IBaseFilter *pSGF = NULL; | |
1319 | |
1320 ISampleGrabber *pSG = NULL; | |
1321 | |
1322 hr=S_OK; | |
25063
29260745e4fa
Pass all available formats to chain building routine and
voroshil
parents:
25061
diff
changeset
|
1323 |
29260745e4fa
Pass all available formats to chain building routine and
voroshil
parents:
25061
diff
changeset
|
1324 //No supported formats |
29260745e4fa
Pass all available formats to chain building routine and
voroshil
parents:
25061
diff
changeset
|
1325 if(!arpmt[0]) |
29260745e4fa
Pass all available formats to chain building routine and
voroshil
parents:
25061
diff
changeset
|
1326 return E_FAIL; |
29260745e4fa
Pass all available formats to chain building routine and
voroshil
parents:
25061
diff
changeset
|
1327 |
24744 | 1328 do{ |
1329 hr = OLE_CALL_ARGS(priv->pBuilder, FindPin, | |
1330 (IUnknown *) pCaptureFilter, | |
1331 PINDIR_OUTPUT, ppin_category, | |
25063
29260745e4fa
Pass all available formats to chain building routine and
voroshil
parents:
25061
diff
changeset
|
1332 &(arpmt[nFormatProbed]->majortype), FALSE, 0, &pCapturePin); |
24744 | 1333 if(FAILED(hr)){ |
1334 mp_msg(MSGT_TV,MSGL_DBG2, "tvi_dshow: FindPin(pCapturePin) call failed. Error:0x%x\n", (unsigned int)hr); | |
1335 break; | |
1336 } | |
1337 /* Addinf SampleGrabber filter for video stream */ | |
1338 hr = CoCreateInstance((GUID *) & CLSID_SampleGrabber, NULL,CLSCTX_INPROC_SERVER, &IID_IBaseFilter,(void *) &pSGF); | |
1339 if(FAILED(hr)){ | |
1340 mp_msg(MSGT_TV,MSGL_DBG2, "tvi_dshow: CoCreateInstance(SampleGrabber) call failed. Error:0x%x\n", (unsigned int)hr); | |
1341 break; | |
1342 } | |
1343 hr = OLE_CALL_ARGS(priv->pGraph, AddFilter, pSGF, L"Sample Grabber"); | |
1344 if(FAILED(hr)){ | |
1345 mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: AddFilter(SampleGrabber) call failed. Error:0x%x\n", (unsigned int)hr); | |
1346 break; | |
1347 } | |
1348 hr = OLE_CALL_ARGS(priv->pBuilder, FindPin, (IUnknown *) pSGF,PINDIR_INPUT, NULL, NULL, FALSE, 0, &pSGIn); | |
1349 if(FAILED(hr)){ | |
1350 mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: FindPin(pSGIn) call failed. Error:0x%x\n", (unsigned int)hr); | |
1351 break; | |
1352 } | |
1353 hr = OLE_CALL_ARGS(priv->pBuilder, FindPin, (IUnknown *) pSGF,PINDIR_OUTPUT, NULL, NULL, FALSE, 0, &pSGOut); | |
1354 if(FAILED(hr)){ | |
1355 mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: FindPin(pSGOut) call failed. Error:0x%x\n", (unsigned int)hr); | |
1356 break; | |
1357 } | |
1358 | |
1359 /* creating ringbuffer for video samples */ | |
1360 priv->pCSGCB = CSampleGrabberCB_Create(pbuf); | |
1361 if(!priv->pCSGCB){ | |
1362 mp_msg(MSGT_TV,MSGL_DBG2, "tvi_dshow: CSampleGrabberCB_Create(pbuf) call failed. Error:0x%x\n", (unsigned int)E_OUTOFMEMORY); | |
1363 break; | |
1364 } | |
1365 | |
1366 /* initializing SampleGrabber filter */ | |
1367 hr = OLE_QUERYINTERFACE(pSGF, IID_ISampleGrabber, pSG); | |
1368 if(FAILED(hr)){ | |
1369 mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: QueryInterface(IID_ISampleGrabber) call failed. Error:0x%x\n", (unsigned int)hr); | |
1370 break; | |
1371 } | |
1372 // hr = OLE_CALL_ARGS(pSG, SetCallback, (ISampleGrabberCB *) pCSGCB, 1); //we want to receive copy of sample's data | |
1373 hr = OLE_CALL_ARGS(pSG, SetCallback, (ISampleGrabberCB *) priv->pCSGCB, 0); //we want to receive sample | |
1374 | |
1375 if(FAILED(hr)){ | |
1376 mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: SetCallback(pSG) call failed. Error:0x%x\n", (unsigned int)hr); | |
1377 break; | |
1378 } | |
1379 hr = OLE_CALL_ARGS(pSG, SetOneShot, FALSE); //... for all frames | |
1380 if(FAILED(hr)){ | |
1381 mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: SetOneShot(pSG) call failed. Error:0x%x\n", (unsigned int)hr); | |
1382 break; | |
1383 } | |
1384 hr = OLE_CALL_ARGS(pSG, SetBufferSamples, FALSE); //... do not buffer samples in sample grabber | |
1385 if(FAILED(hr)){ | |
1386 mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: SetBufferSamples(pSG) call failed. Error:0x%x\n", (unsigned int)hr); | |
1387 break; | |
1388 } | |
25063
29260745e4fa
Pass all available formats to chain building routine and
voroshil
parents:
25061
diff
changeset
|
1389 if(priv->tv_param->normalize_audio_chunks && !memcmp(&(arpmt[nFormatProbed]->majortype),&(MEDIATYPE_Audio),16)){ |
29260745e4fa
Pass all available formats to chain building routine and
voroshil
parents:
25061
diff
changeset
|
1390 set_buffer_preference(20,(WAVEFORMATEX*)(arpmt[nFormatProbed]->pbFormat),pCapturePin,pSGIn); |
25048 | 1391 } |
24744 | 1392 |
25065 | 1393 for(nFormatProbed=0; arpmt[nFormatProbed]; nFormatProbed++) |
1394 { | |
1395 DisplayMediaType("Probing format", arpmt[nFormatProbed]); | |
25066 | 1396 hr = OLE_CALL_ARGS(pSG, SetMediaType, arpmt[nFormatProbed]); //set desired mediatype |
1397 if(FAILED(hr)){ | |
1398 mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: SetMediaType(pSG) call failed. Error:0x%x\n", (unsigned int)hr); | |
1399 continue; | |
1400 } | |
1401 /* connecting filters together: VideoCapture --> SampleGrabber */ | |
1402 hr = OLE_CALL_ARGS(priv->pGraph, Connect, pCapturePin, pSGIn); | |
1403 if(FAILED(hr)){ | |
1404 mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: Unable to create pCapturePin<->pSGIn connection. Error:0x%x\n", (unsigned int)hr); | |
1405 continue; | |
1406 } | |
25065 | 1407 break; |
1408 } | |
1409 OLE_RELEASE_SAFE(pSG); | |
1410 | |
1411 if(!arpmt[nFormatProbed]) | |
1412 { | |
1413 mp_msg(MSGT_TV, MSGL_WARN, "tvi_dshow: Unable to negotiate media format\n"); | |
1414 hr = E_FAIL; | |
24744 | 1415 break; |
1416 } | |
25063
29260745e4fa
Pass all available formats to chain building routine and
voroshil
parents:
25061
diff
changeset
|
1417 |
29260745e4fa
Pass all available formats to chain building routine and
voroshil
parents:
25061
diff
changeset
|
1418 hr = OLE_CALL_ARGS(pCapturePin, ConnectionMediaType, pmt); |
25029
c9f20e41bc13
Make sure that mplayer will receive actual media type
voroshil
parents:
25028
diff
changeset
|
1419 if(FAILED(hr)) |
c9f20e41bc13
Make sure that mplayer will receive actual media type
voroshil
parents:
25028
diff
changeset
|
1420 { |
c9f20e41bc13
Make sure that mplayer will receive actual media type
voroshil
parents:
25028
diff
changeset
|
1421 mp_msg(MSGT_TV, MSGL_WARN, MSGTR_TVI_DS_GetActualMediatypeFailed, (unsigned int)hr); |
c9f20e41bc13
Make sure that mplayer will receive actual media type
voroshil
parents:
25028
diff
changeset
|
1422 } |
24744 | 1423 |
1424 if(priv->tv_param->hidden_video_renderer){ | |
1425 IEnumFilters* pEnum; | |
1426 IBaseFilter* pFilter; | |
1427 | |
1428 hr=OLE_CALL_ARGS(priv->pBuilder,RenderStream,NULL,NULL,(IUnknown*)pCapturePin,NULL,NULL); | |
1429 | |
1430 OLE_CALL_ARGS(priv->pGraph, EnumFilters, &pEnum); | |
1431 while (OLE_CALL_ARGS(pEnum, Next, 1, &pFilter, NULL) == S_OK) { | |
1432 LPVIDEOWINDOW pVideoWindow; | |
1433 hr = OLE_QUERYINTERFACE(pFilter, IID_IVideoWindow, pVideoWindow); | |
1434 if (SUCCEEDED(hr)) | |
1435 { | |
1436 OLE_CALL_ARGS(pVideoWindow,put_Visible,/* OAFALSE*/ 0); | |
1437 OLE_CALL_ARGS(pVideoWindow,put_AutoShow,/* OAFALSE*/ 0); | |
1438 OLE_RELEASE_SAFE(pVideoWindow); | |
1439 } | |
1440 OLE_RELEASE_SAFE(pFilter); | |
1441 } | |
1442 OLE_RELEASE_SAFE(pEnum); | |
1443 }else | |
1444 { | |
25052
7b2b17b57cf7
Disable terminating directshow chains with NullRenderer filter,
voroshil
parents:
25051
diff
changeset
|
1445 #if 0 |
7b2b17b57cf7
Disable terminating directshow chains with NullRenderer filter,
voroshil
parents:
25051
diff
changeset
|
1446 /* |
7b2b17b57cf7
Disable terminating directshow chains with NullRenderer filter,
voroshil
parents:
25051
diff
changeset
|
1447 Code below is disabled, because terminating chain with NullRenderer leads to jerky video. |
7b2b17b57cf7
Disable terminating directshow chains with NullRenderer filter,
voroshil
parents:
25051
diff
changeset
|
1448 Perhaps, this happens because NullRenderer filter discards each received |
7b2b17b57cf7
Disable terminating directshow chains with NullRenderer filter,
voroshil
parents:
25051
diff
changeset
|
1449 frame while discarded frames causes live source filter to dramatically reduce frame rate. |
7b2b17b57cf7
Disable terminating directshow chains with NullRenderer filter,
voroshil
parents:
25051
diff
changeset
|
1450 */ |
24744 | 1451 /* adding sink for video stream */ |
1452 hr = CoCreateInstance((GUID *) & CLSID_NullRenderer, NULL,CLSCTX_INPROC_SERVER, &IID_IBaseFilter,(void *) &pNR); | |
1453 if(FAILED(hr)){ | |
1454 mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: CoCreateInstance(NullRenderer) call failed. Error:0x%x\n", (unsigned int)hr); | |
1455 break; | |
1456 } | |
1457 hr = OLE_CALL_ARGS(priv->pGraph, AddFilter, pNR, L"Null Renderer"); | |
1458 if(FAILED(hr)){ | |
1459 mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: AddFilter(NullRenderer) call failed. Error:0x%x\n", (unsigned int)hr); | |
1460 break; | |
1461 } | |
1462 hr = OLE_CALL_ARGS(priv->pBuilder, FindPin, (IUnknown *) pNR,PINDIR_INPUT, NULL, NULL, FALSE, 0, &pNRIn); | |
1463 if(FAILED(hr)){ | |
1464 mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: FindPin(pNRIn) call failed. Error:0x%x\n", (unsigned int)hr); | |
1465 break; | |
1466 } | |
1467 /* | |
1468 Prevent ending VBI chain with NullRenderer filter, because this causes VBI pin disconnection | |
1469 */ | |
25063
29260745e4fa
Pass all available formats to chain building routine and
voroshil
parents:
25061
diff
changeset
|
1470 if(memcmp(&(arpmt[nFormatProbed]->majortype),&MEDIATYPE_VBI,16)){ |
24744 | 1471 /* connecting filters together: SampleGrabber --> NullRenderer */ |
1472 hr = OLE_CALL_ARGS(priv->pGraph, Connect, pSGOut, pNRIn); | |
1473 if(FAILED(hr)){ | |
1474 mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: Unable to create pSGOut<->pNRIn connection. Error:0x%x\n", (unsigned int)hr); | |
1475 break; | |
1476 } | |
1477 } | |
25052
7b2b17b57cf7
Disable terminating directshow chains with NullRenderer filter,
voroshil
parents:
25051
diff
changeset
|
1478 #endif |
24744 | 1479 } |
1480 | |
1481 hr = S_OK; | |
1482 } while(0); | |
25029
c9f20e41bc13
Make sure that mplayer will receive actual media type
voroshil
parents:
25028
diff
changeset
|
1483 |
24744 | 1484 OLE_RELEASE_SAFE(pSGF); |
1485 OLE_RELEASE_SAFE(pSGIn); | |
1486 OLE_RELEASE_SAFE(pSGOut); | |
1487 OLE_RELEASE_SAFE(pNR); | |
1488 OLE_RELEASE_SAFE(pNRIn); | |
1489 OLE_RELEASE_SAFE(pCapturePin); | |
1490 | |
1491 return hr; | |
1492 } | |
1493 | |
1494 /** | |
1495 * \brief configures crossbar for grabbing video stream from given input | |
1496 * | |
1497 * \param priv driver's private data | |
1498 * \param input index of available video input to get data from | |
1499 * | |
1500 * \return TVI_CONTROL_TRUE success | |
1501 * \return TVI_CONTROL_FALSE error | |
1502 */ | |
1503 static int set_crossbar_input(priv_t * priv, int input) | |
1504 { | |
1505 HRESULT hr; | |
1506 int i, nVideoDecoder, nAudioDecoder; | |
1507 long lInput, lInputRelated, lRelated, lPhysicalType, lOutputPins, | |
1508 lInputPins; | |
1509 | |
1510 mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: Configuring crossbar\n"); | |
1511 if (!priv->pCrossbar || input < 0 | |
1512 || input >= tv_available_inputs_count) | |
1513 return TVI_CONTROL_FALSE; | |
1514 | |
1515 OLE_CALL_ARGS(priv->pCrossbar, get_PinCounts, &lOutputPins, &lInputPins); | |
1516 | |
1517 lInput = tv_available_inputs[input]; | |
1518 | |
1519 if (lInput < 0 || lInput >= lInputPins) | |
1520 return TVI_CONTROL_FALSE; | |
1521 | |
1522 OLE_CALL_ARGS(priv->pCrossbar, get_CrossbarPinInfo, 1 /* input */ , lInput, | |
1523 &lInputRelated, &lPhysicalType); | |
1524 | |
1525 nVideoDecoder = nAudioDecoder = -1; | |
1526 for (i = 0; i < lOutputPins; i++) { | |
1527 OLE_CALL_ARGS(priv->pCrossbar, get_CrossbarPinInfo, 0 /*output */ , i, | |
1528 &lRelated, &lPhysicalType); | |
1529 if (lPhysicalType == PhysConn_Video_VideoDecoder) | |
1530 nVideoDecoder = i; | |
1531 if (lPhysicalType == PhysConn_Audio_AudioDecoder) | |
1532 nAudioDecoder = i; | |
1533 } | |
1534 if (nVideoDecoder >= 0) { | |
1535 //connecting given input with video decoder | |
1536 hr = OLE_CALL_ARGS(priv->pCrossbar, Route, nVideoDecoder, lInput); | |
1537 if (hr != S_OK) { | |
1538 mp_msg(MSGT_TV,MSGL_ERR,MSGTR_TVI_DS_UnableConnectInputVideoDecoder, (unsigned int)hr); | |
1539 return TVI_CONTROL_FALSE; | |
1540 } | |
1541 } | |
1542 if (nAudioDecoder >= 0 && lInputRelated >= 0) { | |
1543 hr = OLE_CALL_ARGS(priv->pCrossbar, Route, nAudioDecoder, | |
1544 lInputRelated); | |
1545 if (hr != S_OK) { | |
1546 mp_msg(MSGT_TV,MSGL_ERR,MSGTR_TVI_DS_UnableConnectInputAudioDecoder, (unsigned int)hr); | |
1547 return TVI_CONTROL_FALSE; | |
1548 } | |
1549 } | |
1550 return TVI_CONTROL_TRUE; | |
1551 } | |
1552 | |
1553 /** | |
1554 * \brief adjusts video control (hue,saturation,contrast,brightess) | |
1555 * | |
1556 * \param priv driver's private data | |
1557 * \param control which control to adjust | |
1558 * \param value new value for control (0-100) | |
1559 * | |
1560 * \return TVI_CONTROL_TRUE success | |
1561 * \return TVI_CONTROL_FALSE error | |
1562 */ | |
1563 static int set_control(priv_t * priv, int control, int value) | |
1564 { | |
1565 long lMin, lMax, lStepping, lDefault, lFlags, lValue; | |
1566 HRESULT hr; | |
1567 | |
1568 mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: set_control called\n"); | |
1569 if (value < -100 || value > 100 || !priv->pVideoProcAmp) | |
1570 return TVI_CONTROL_FALSE; | |
1571 | |
1572 hr = OLE_CALL_ARGS(priv->pVideoProcAmp, GetRange, control, | |
1573 &lMin, &lMax, &lStepping, &lDefault, &lFlags); | |
1574 if (FAILED(hr) || lFlags != VideoProcAmp_Flags_Manual) | |
1575 return TVI_CONTROL_FALSE; | |
1576 | |
1577 lValue = lMin + (value + 100) * (lMax - lMin) / 200; | |
1578 /* | |
1579 Workaround for ATI AIW 7500. The driver reports: max=255, stepping=256 | |
1580 */ | |
1581 if (lStepping > lMax) { | |
1582 mp_msg(MSGT_TV, MSGL_DBG3, | |
1583 "tvi_dshow: Stepping (%ld) is bigger than max value (%ld) for control %d. Assuming 1\n", | |
1584 lStepping, lMax,control); | |
1585 lStepping = 1; | |
1586 } | |
1587 lValue -= lValue % lStepping; | |
1588 hr = OLE_CALL_ARGS(priv->pVideoProcAmp, Set, control, lValue, | |
1589 VideoProcAmp_Flags_Manual); | |
1590 if (FAILED(hr)) | |
1591 return TVI_CONTROL_FALSE; | |
1592 | |
1593 return TVI_CONTROL_TRUE; | |
1594 } | |
1595 | |
1596 /** | |
1597 * \brief get current value of video control (hue,saturation,contrast,brightess) | |
1598 * | |
1599 * \param priv driver's private data | |
1600 * \param control which control to adjust | |
1601 * \param pvalue address of variable thar receives current value | |
1602 * | |
1603 * \return TVI_CONTROL_TRUE success | |
1604 * \return TVI_CONTROL_FALSE error | |
1605 */ | |
1606 static int get_control(priv_t * priv, int control, int *pvalue) | |
1607 { | |
1608 long lMin, lMax, lStepping, lDefault, lFlags, lValue; | |
1609 HRESULT hr; | |
1610 | |
1611 mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: get_control called\n"); | |
1612 if (!pvalue || !priv->pVideoProcAmp) | |
1613 return TVI_CONTROL_FALSE; | |
1614 | |
1615 hr = OLE_CALL_ARGS(priv->pVideoProcAmp, GetRange, control, | |
1616 &lMin, &lMax, &lStepping, &lDefault, &lFlags); | |
1617 if (FAILED(hr)) | |
1618 return TVI_CONTROL_FALSE; | |
1619 if (lMin == lMax) { | |
1620 *pvalue = lMin; | |
1621 return TVI_CONTROL_TRUE; | |
1622 } | |
1623 | |
1624 hr = OLE_CALL_ARGS(priv->pVideoProcAmp, Get, control, &lValue, &lFlags); | |
1625 if (FAILED(hr)) | |
1626 return TVI_CONTROL_FALSE; | |
1627 | |
1628 *pvalue = 200 * (lValue - lMin) / (lMax - lMin) - 100; | |
1629 | |
1630 return TVI_CONTROL_TRUE; | |
1631 } | |
1632 | |
1633 /** | |
25053
086c2accaaa2
Service routine for constructing AM_MEDIA_TYPE structure from
voroshil
parents:
25052
diff
changeset
|
1634 * \brief create AM_MEDIA_TYPE structure, corresponding to given FourCC code and width/height/fps |
086c2accaaa2
Service routine for constructing AM_MEDIA_TYPE structure from
voroshil
parents:
25052
diff
changeset
|
1635 * \param fcc FourCC code for video format |
086c2accaaa2
Service routine for constructing AM_MEDIA_TYPE structure from
voroshil
parents:
25052
diff
changeset
|
1636 * \param width picture width |
086c2accaaa2
Service routine for constructing AM_MEDIA_TYPE structure from
voroshil
parents:
25052
diff
changeset
|
1637 * \param height pciture height |
086c2accaaa2
Service routine for constructing AM_MEDIA_TYPE structure from
voroshil
parents:
25052
diff
changeset
|
1638 * \param fps frames per second (required for bitrate calculation) |
086c2accaaa2
Service routine for constructing AM_MEDIA_TYPE structure from
voroshil
parents:
25052
diff
changeset
|
1639 * |
086c2accaaa2
Service routine for constructing AM_MEDIA_TYPE structure from
voroshil
parents:
25052
diff
changeset
|
1640 * \return pointer to AM_MEDIA_TYPE structure if success, NULL - otherwise |
086c2accaaa2
Service routine for constructing AM_MEDIA_TYPE structure from
voroshil
parents:
25052
diff
changeset
|
1641 */ |
086c2accaaa2
Service routine for constructing AM_MEDIA_TYPE structure from
voroshil
parents:
25052
diff
changeset
|
1642 static AM_MEDIA_TYPE* create_video_format(int fcc, int width, int height, int fps) |
086c2accaaa2
Service routine for constructing AM_MEDIA_TYPE structure from
voroshil
parents:
25052
diff
changeset
|
1643 { |
086c2accaaa2
Service routine for constructing AM_MEDIA_TYPE structure from
voroshil
parents:
25052
diff
changeset
|
1644 int i; |
086c2accaaa2
Service routine for constructing AM_MEDIA_TYPE structure from
voroshil
parents:
25052
diff
changeset
|
1645 AM_MEDIA_TYPE mt; |
086c2accaaa2
Service routine for constructing AM_MEDIA_TYPE structure from
voroshil
parents:
25052
diff
changeset
|
1646 VIDEOINFOHEADER vHdr; |
086c2accaaa2
Service routine for constructing AM_MEDIA_TYPE structure from
voroshil
parents:
25052
diff
changeset
|
1647 |
086c2accaaa2
Service routine for constructing AM_MEDIA_TYPE structure from
voroshil
parents:
25052
diff
changeset
|
1648 /* Check given fcc in lookup table*/ |
086c2accaaa2
Service routine for constructing AM_MEDIA_TYPE structure from
voroshil
parents:
25052
diff
changeset
|
1649 for(i=0; img_fmt_list[i].fmt && img_fmt_list[i].fmt!=fcc; i++) /* NOTHING */; |
086c2accaaa2
Service routine for constructing AM_MEDIA_TYPE structure from
voroshil
parents:
25052
diff
changeset
|
1650 if(!img_fmt_list[i].fmt) |
086c2accaaa2
Service routine for constructing AM_MEDIA_TYPE structure from
voroshil
parents:
25052
diff
changeset
|
1651 return NULL; |
086c2accaaa2
Service routine for constructing AM_MEDIA_TYPE structure from
voroshil
parents:
25052
diff
changeset
|
1652 |
086c2accaaa2
Service routine for constructing AM_MEDIA_TYPE structure from
voroshil
parents:
25052
diff
changeset
|
1653 memset(&mt, 0, sizeof(AM_MEDIA_TYPE)); |
086c2accaaa2
Service routine for constructing AM_MEDIA_TYPE structure from
voroshil
parents:
25052
diff
changeset
|
1654 memset(&vHdr, 0, sizeof(VIDEOINFOHEADER)); |
086c2accaaa2
Service routine for constructing AM_MEDIA_TYPE structure from
voroshil
parents:
25052
diff
changeset
|
1655 |
086c2accaaa2
Service routine for constructing AM_MEDIA_TYPE structure from
voroshil
parents:
25052
diff
changeset
|
1656 vHdr.bmiHeader.biSize = sizeof(vHdr.bmiHeader); |
086c2accaaa2
Service routine for constructing AM_MEDIA_TYPE structure from
voroshil
parents:
25052
diff
changeset
|
1657 vHdr.bmiHeader.biWidth = width; |
086c2accaaa2
Service routine for constructing AM_MEDIA_TYPE structure from
voroshil
parents:
25052
diff
changeset
|
1658 vHdr.bmiHeader.biHeight = height; |
086c2accaaa2
Service routine for constructing AM_MEDIA_TYPE structure from
voroshil
parents:
25052
diff
changeset
|
1659 //FIXME: is biPlanes required too? |
086c2accaaa2
Service routine for constructing AM_MEDIA_TYPE structure from
voroshil
parents:
25052
diff
changeset
|
1660 //vHdr.bmiHeader.biPlanes = img_fmt_list[i].nPlanes; |
086c2accaaa2
Service routine for constructing AM_MEDIA_TYPE structure from
voroshil
parents:
25052
diff
changeset
|
1661 vHdr.bmiHeader.biBitCount = img_fmt_list[i].nBits; |
086c2accaaa2
Service routine for constructing AM_MEDIA_TYPE structure from
voroshil
parents:
25052
diff
changeset
|
1662 vHdr.bmiHeader.biCompression = img_fmt_list[i].nCompression; |
086c2accaaa2
Service routine for constructing AM_MEDIA_TYPE structure from
voroshil
parents:
25052
diff
changeset
|
1663 vHdr.bmiHeader.biSizeImage = width * height * img_fmt_list[i].nBits / 8; |
086c2accaaa2
Service routine for constructing AM_MEDIA_TYPE structure from
voroshil
parents:
25052
diff
changeset
|
1664 vHdr.dwBitRate = vHdr.bmiHeader.biSizeImage * 8 * fps; |
086c2accaaa2
Service routine for constructing AM_MEDIA_TYPE structure from
voroshil
parents:
25052
diff
changeset
|
1665 |
086c2accaaa2
Service routine for constructing AM_MEDIA_TYPE structure from
voroshil
parents:
25052
diff
changeset
|
1666 mt.pbFormat = (char*)&vHdr; |
086c2accaaa2
Service routine for constructing AM_MEDIA_TYPE structure from
voroshil
parents:
25052
diff
changeset
|
1667 mt.cbFormat = sizeof(vHdr); |
086c2accaaa2
Service routine for constructing AM_MEDIA_TYPE structure from
voroshil
parents:
25052
diff
changeset
|
1668 |
086c2accaaa2
Service routine for constructing AM_MEDIA_TYPE structure from
voroshil
parents:
25052
diff
changeset
|
1669 mt.majortype = MEDIATYPE_Video; |
086c2accaaa2
Service routine for constructing AM_MEDIA_TYPE structure from
voroshil
parents:
25052
diff
changeset
|
1670 mt.subtype = *img_fmt_list[i].subtype; |
086c2accaaa2
Service routine for constructing AM_MEDIA_TYPE structure from
voroshil
parents:
25052
diff
changeset
|
1671 mt.formattype = FORMAT_VideoInfo; |
086c2accaaa2
Service routine for constructing AM_MEDIA_TYPE structure from
voroshil
parents:
25052
diff
changeset
|
1672 |
086c2accaaa2
Service routine for constructing AM_MEDIA_TYPE structure from
voroshil
parents:
25052
diff
changeset
|
1673 mt.bFixedSizeSamples = 1; |
086c2accaaa2
Service routine for constructing AM_MEDIA_TYPE structure from
voroshil
parents:
25052
diff
changeset
|
1674 mt.bTemporalCompression = 0; |
086c2accaaa2
Service routine for constructing AM_MEDIA_TYPE structure from
voroshil
parents:
25052
diff
changeset
|
1675 mt.lSampleSize = vHdr.bmiHeader.biSizeImage; |
086c2accaaa2
Service routine for constructing AM_MEDIA_TYPE structure from
voroshil
parents:
25052
diff
changeset
|
1676 |
086c2accaaa2
Service routine for constructing AM_MEDIA_TYPE structure from
voroshil
parents:
25052
diff
changeset
|
1677 return CreateMediaType(&mt); |
086c2accaaa2
Service routine for constructing AM_MEDIA_TYPE structure from
voroshil
parents:
25052
diff
changeset
|
1678 } |
086c2accaaa2
Service routine for constructing AM_MEDIA_TYPE structure from
voroshil
parents:
25052
diff
changeset
|
1679 |
086c2accaaa2
Service routine for constructing AM_MEDIA_TYPE structure from
voroshil
parents:
25052
diff
changeset
|
1680 /** |
24744 | 1681 * \brief extracts fcc,width,height from AM_MEDIA_TYPE |
1682 * | |
1683 * \param pmt pointer to AM_MEDIA_TYPE to extract data from | |
1684 * \param pfcc address of variable that receives FourCC | |
1685 * \param pwidth address of variable that receives width | |
1686 * \param pheight address of variable that recevies height | |
1687 * | |
1688 * \return 1 if data extracted successfully, 0 - otherwise | |
1689 */ | |
1690 static int extract_video_format(AM_MEDIA_TYPE * pmt, int *pfcc, | |
1691 int *pwidth, int *pheight) | |
1692 { | |
1693 mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: extract_video_format called\n"); | |
1694 if (!pmt) | |
1695 return 0; | |
1696 if (!pmt->pbFormat) | |
1697 return 0; | |
1698 if (memcmp(&(pmt->formattype), &FORMAT_VideoInfo, 16) != 0) | |
1699 return 0; | |
1700 if (pfcc) | |
1701 *pfcc = subtype2imgfmt(&(pmt->subtype)); | |
1702 if (pwidth) | |
1703 *pwidth = ((VIDEOINFOHEADER *) pmt->pbFormat)->bmiHeader.biWidth; | |
1704 if (pheight) | |
1705 *pheight = ((VIDEOINFOHEADER *) pmt->pbFormat)->bmiHeader.biHeight; | |
1706 return 1; | |
1707 } | |
1708 | |
1709 /** | |
1710 * \brief extracts samplerate,bits,channels from AM_MEDIA_TYPE | |
1711 * | |
1712 * \param pmt pointer to AM_MEDIA_TYPE to extract data from | |
1713 * \param pfcc address of variable that receives samplerate | |
1714 * \param pwidth address of variable that receives number of bits per sample | |
1715 * \param pheight address of variable that recevies number of channels | |
1716 * | |
1717 * \return 1 if data extracted successfully, 0 - otherwise | |
1718 */ | |
1719 static int extract_audio_format(AM_MEDIA_TYPE * pmt, int *psamplerate, | |
1720 int *pbits, int *pchannels) | |
1721 { | |
1722 mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: extract_audio_format called\n"); | |
1723 if (!pmt) | |
1724 return 0; | |
1725 if (!pmt->pbFormat) | |
1726 return 0; | |
1727 if (memcmp(&(pmt->formattype), &FORMAT_WaveFormatEx, 16) != 0) | |
1728 return 0; | |
1729 if (psamplerate) | |
1730 *psamplerate = ((WAVEFORMATEX *) pmt->pbFormat)->nSamplesPerSec; | |
1731 if (pbits) | |
1732 *pbits = ((WAVEFORMATEX *) pmt->pbFormat)->wBitsPerSample; | |
1733 if (pchannels) | |
1734 *pchannels = ((WAVEFORMATEX *) pmt->pbFormat)->nChannels; | |
1735 return 1; | |
1736 } | |
1737 | |
1738 /** | |
1739 * \brief checks if AM_MEDIA_TYPE compatible with given samplerate,bits,channels | |
1740 * | |
1741 * \param pmt pointer to AM_MEDIA_TYPE for check | |
1742 * \param samplerate audio samplerate | |
1743 * \param bits bits per sample | |
1744 * \param channels number of audio channels | |
1745 * | |
1746 * \return 1 if AM_MEDIA_TYPE compatible | |
1747 * \return 0 if not | |
1748 */ | |
1749 static int check_audio_format(AM_MEDIA_TYPE * pmt, int samplerate, | |
1750 int bits, int channels) | |
1751 { | |
1752 mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: check_audio_format called\n"); | |
1753 if (!pmt) | |
1754 return 0; | |
1755 if (memcmp(&(pmt->majortype), &MEDIATYPE_Audio, 16) != 0) | |
1756 return 0; | |
1757 if (memcmp(&(pmt->subtype), &MEDIASUBTYPE_PCM, 16) != 0) | |
1758 return 0; | |
1759 if (memcmp(&(pmt->formattype), &FORMAT_WaveFormatEx, 16) != 0) | |
1760 return 0; | |
1761 if (!pmt->pbFormat) | |
1762 return 0; | |
1763 if (((WAVEFORMATEX *) pmt->pbFormat)->nSamplesPerSec != samplerate) | |
1764 return 0; | |
1765 if (((WAVEFORMATEX *) pmt->pbFormat)->wBitsPerSample != bits) | |
1766 return 0; | |
1767 if (channels > 0 | |
1768 && ((WAVEFORMATEX *) pmt->pbFormat)->nChannels != channels) | |
1769 return 0; | |
1770 | |
1771 return 1; | |
1772 } | |
1773 | |
1774 /** | |
1775 * \brief checks if AM_MEDIA_TYPE compatible with given fcc,width,height | |
1776 * | |
1777 * \param pmt pointer to AM_MEDIA_TYPE for check | |
1778 * \param fcc FourCC (compression) | |
1779 * \param width width of picture | |
1780 * \param height height of picture | |
1781 * | |
1782 * \return 1 if AM_MEDIA_TYPE compatible | |
1783 & \return 0 if not | |
1784 * | |
1785 * \note | |
1786 * width and height are currently not used | |
1787 * | |
1788 * \todo | |
1789 * add width/height check | |
1790 */ | |
1791 static int check_video_format(AM_MEDIA_TYPE * pmt, int fcc, int width, | |
1792 int height) | |
1793 { | |
1794 mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: check_video_format called\n"); | |
1795 if (!pmt) | |
1796 return 0; | |
1797 if (memcmp(&(pmt->majortype), &MEDIATYPE_Video, 16) != 0) | |
1798 return 0; | |
1799 if (subtype2imgfmt(&(pmt->subtype)) != fcc) | |
1800 return 0; | |
1801 return 1; | |
1802 } | |
1803 | |
1804 /** | |
1805 * \brief converts DirectShow subtype to MPlayer's IMGFMT | |
1806 * | |
1807 * \param subtype DirectShow subtype for video format | |
1808 * | |
1809 * \return MPlayer's IMGFMT or 0 if error occured | |
1810 */ | |
1811 static int subtype2imgfmt(const GUID * subtype) | |
1812 { | |
1813 int i; | |
1814 for (i = 0; img_fmt_list[i].fmt; i++) { | |
1815 if (memcmp(subtype, img_fmt_list[i].subtype, 16) == 0) | |
1816 return img_fmt_list[i].fmt; | |
1817 } | |
1818 return 0; | |
1819 } | |
1820 | |
1821 /** | |
1822 * \brief prints filter name and it pins | |
1823 * | |
1824 * \param pFilter - IBaseFilter to get data from | |
1825 * | |
1826 * \return S_OK if success, error code otherwise | |
1827 */ | |
1828 static HRESULT show_filter_info(IBaseFilter * pFilter) | |
1829 { | |
1830 char tmp[200]; | |
1831 FILTER_INFO fi; | |
1832 LPENUMPINS pEnum = 0; | |
1833 IPin *pPin = 0; | |
1834 PIN_DIRECTION ThisPinDir; | |
1835 PIN_INFO pi; | |
1836 HRESULT hr; | |
1837 int i; | |
1838 | |
1839 mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: show_filter_info called\n"); | |
1840 memset(&fi, 0, sizeof(fi)); | |
1841 memset(tmp, 0, 200); | |
1842 | |
1843 OLE_CALL_ARGS(pFilter, QueryFilterInfo, &fi); | |
1844 OLE_RELEASE_SAFE(fi.pGraph); | |
1845 wtoa(fi.achName, tmp, 200); | |
1846 mp_msg(MSGT_TV, MSGL_DBG2, "tvi_dshow: BaseFilter (%p): Name=%s, Graph=%p output pins:", | |
1847 pFilter, tmp, fi.pGraph); | |
1848 hr = OLE_CALL_ARGS(pFilter, EnumPins, &pEnum); | |
1849 if (FAILED(hr)) | |
1850 return hr; | |
1851 i = 0; | |
1852 while (OLE_CALL_ARGS(pEnum, Next, 1, &pPin, NULL) == S_OK) { | |
1853 memset(&pi, 0, sizeof(pi)); | |
1854 memset(tmp, 0, 200); | |
1855 OLE_CALL_ARGS(pPin, QueryDirection, &ThisPinDir); | |
1856 if (ThisPinDir == PINDIR_OUTPUT) { | |
1857 OLE_CALL_ARGS(pPin, QueryPinInfo, &pi); | |
1858 wtoa(pi.achName, tmp, 200); | |
1859 OLE_RELEASE_SAFE(pi.pFilter); | |
1860 mp_msg(MSGT_TV, MSGL_DBG2, " %d=%s", i, tmp); | |
1861 mp_msg(MSGT_TV, MSGL_DBG3, " (%p)", pPin); | |
1862 mp_msg(MSGT_TV, MSGL_DBG2, ";"); | |
1863 OLE_RELEASE_SAFE(pPin); | |
1864 i++; | |
1865 } | |
1866 } | |
1867 mp_msg(MSGT_TV, MSGL_DBG2, "\n"); | |
1868 OLE_RELEASE_SAFE(pEnum); | |
1869 return S_OK; | |
1870 } | |
1871 | |
1872 /** | |
1873 * \brief gets device's frendly in ANSI encoding | |
1874 * | |
1875 * \param pM IMoniker interface, got in enumeration process | |
1876 * \param category device category | |
1877 * | |
1878 * \return TVI_CONTROL_TRUE if operation succeded, TVI_CONTROL_FALSE - otherwise | |
1879 */ | |
1880 static int get_device_name(IMoniker * pM, char *pBuf, int nLen) | |
1881 { | |
1882 HRESULT hr; | |
1883 VARIANT var; | |
1884 IPropertyBag *pPropBag; | |
1885 hr = OLE_CALL_ARGS(pM, BindToStorage, 0, 0, &IID_IPropertyBag,(void *) &pPropBag); | |
1886 if (FAILED(hr)) { | |
1887 mp_msg(MSGT_TV, MSGL_DBG2, "tvi_dshow: Call to BindToStorage failed\n"); | |
1888 return TVI_CONTROL_FALSE; | |
1889 } | |
1890 var.vt = VT_BSTR; | |
1891 hr = OLE_CALL_ARGS(pPropBag, Read, L"Description", (LPVARIANT) & var, | |
1892 NULL); | |
1893 if (FAILED(hr)) { | |
1894 hr = OLE_CALL_ARGS(pPropBag, Read, L"FriendlyName", (LPVARIANT) & var, | |
1895 NULL); | |
1896 } | |
1897 OLE_RELEASE_SAFE(pPropBag); | |
1898 if (SUCCEEDED(hr)) { | |
1899 wtoa(var.bstrVal, pBuf, nLen); | |
1900 return TVI_CONTROL_TRUE; | |
1901 } | |
1902 return TVI_CONTROL_FALSE; | |
1903 } | |
1904 | |
1905 /** | |
1906 * \brief find capture device at given index | |
1907 * | |
1908 * \param index device index to search for (-1 mean only print available) | |
1909 * \param category device category | |
1910 * | |
1911 * \return IBaseFilter interface for capture device with given index | |
1912 * | |
1913 * Sample values for category: | |
1914 * CLSID_VideoInputDeviceCategory - Video Capture Sources | |
1915 * CLSID_AudioInputDeviceCategory - Audio Capture Sources | |
1916 * See DirectShow SDK documentation for other possible values | |
1917 */ | |
1918 static IBaseFilter *find_capture_device(int index, REFCLSID category) | |
1919 { | |
1920 IBaseFilter *pFilter = NULL; | |
1921 ICreateDevEnum *pDevEnum = NULL; | |
1922 IEnumMoniker *pClassEnum = NULL; | |
1923 IMoniker *pM; | |
1924 HRESULT hr; | |
1925 ULONG cFetched; | |
1926 int i; | |
1927 char tmp[DEVICE_NAME_MAX_LEN + 1]; | |
1928 hr = CoCreateInstance((GUID *) & CLSID_SystemDeviceEnum, NULL, | |
1929 CLSCTX_INPROC_SERVER, &IID_ICreateDevEnum, | |
1930 (void *) &pDevEnum); | |
1931 if (FAILED(hr)) { | |
1932 mp_msg(MSGT_TV, MSGL_DBG2, "tvi_dshow: Unable to create device enumerator\n"); | |
1933 return NULL; | |
1934 } | |
1935 | |
1936 hr = OLE_CALL_ARGS(pDevEnum, CreateClassEnumerator, category, &pClassEnum, 0); | |
1937 OLE_RELEASE_SAFE(pDevEnum); | |
1938 if (FAILED(hr)) { | |
1939 mp_msg(MSGT_TV, MSGL_DBG2, "tvi_dshow: Unable to create class enumerator\n"); | |
1940 return NULL; | |
1941 } | |
1942 if (hr == S_FALSE) { | |
1943 mp_msg(MSGT_TV, MSGL_DBG2, "tvi_dshow: No capture devices found\n"); | |
1944 return NULL; | |
1945 } | |
1946 | |
1947 OLE_CALL(pClassEnum,Reset); | |
1948 for (i = 0; OLE_CALL_ARGS(pClassEnum, Next, 1, &pM, &cFetched) == S_OK; i++) { | |
1949 if(get_device_name(pM, tmp, DEVICE_NAME_MAX_LEN)!=TVI_CONTROL_TRUE) | |
1950 mp_msg(MSGT_TV, MSGL_ERR, MSGTR_TVI_DS_UnableGetDeviceName, i); | |
1951 else | |
1952 mp_msg(MSGT_TV, MSGL_V, MSGTR_TVI_DS_DeviceName, i, tmp); | |
1953 if (index != -1 && i == index) { | |
1954 mp_msg(MSGT_TV, MSGL_INFO, MSGTR_TVI_DS_UsingDevice, index, tmp); | |
1955 hr = OLE_CALL_ARGS(pM, BindToObject, 0, 0, &IID_IBaseFilter,(void *) &pFilter); | |
1956 if (FAILED(hr)) | |
1957 pFilter = NULL; | |
1958 } | |
1959 OLE_RELEASE_SAFE(pM); | |
1960 } | |
1961 if (index != -1 && !pFilter) { | |
1962 mp_msg(MSGT_TV, MSGL_ERR, MSGTR_TVI_DS_DeviceNotFound, | |
1963 index); | |
1964 } | |
1965 OLE_RELEASE_SAFE(pClassEnum); | |
1966 | |
1967 return pFilter; | |
1968 } | |
1969 | |
1970 /** | |
1971 * \brief get array of available formats through call to IAMStreamConfig::GetStreamCaps | |
1972 * | |
1973 * \param[in] pVideoStreamConfig IAMStreamConfig of used capture device's output pin | |
1974 * \param[in] pMediaType MEDIATYPE_Video or MEDIATYPE_Audio | |
1975 * \param[out] parpmtMedia address of variable that receives pointer to array of AM_MEDIA_TYPE structures | |
1976 * \param[out] parCaps address of variable thar receives pointer to array of VIDEOSTREAM_CONFIG_CAPS or AUDIO_STREAM_CONFIG_CAPS | |
1977 * | |
1978 * \return S_OK success | |
1979 * \return E_POINTER one of parameters is NULL | |
1980 * \return E_FAIL required size of buffer is unknown for given media type | |
1981 * \return E_OUTOFMEMORY not enough memory | |
1982 * \return other error code from called methods | |
1983 * | |
1984 * \remarks | |
1985 * last item or returned arrays will be NULL | |
1986 */ | |
1987 static HRESULT get_available_formats_stream(IAMStreamConfig * | |
1988 pStreamConfig, | |
1989 const GUID * pMediaType, | |
1990 AM_MEDIA_TYPE *** parpmtMedia, | |
1991 void ***parCaps) | |
1992 { | |
1993 AM_MEDIA_TYPE **arpmt; | |
1994 void **pBuf=NULL; | |
1995 | |
1996 HRESULT hr; | |
1997 int i, count, size; | |
1998 int done; | |
1999 | |
2000 mp_msg(MSGT_TV, MSGL_DBG4, | |
2001 "tvi_dshow: get_available_formats_stream called\n"); | |
2002 | |
2003 if (!pStreamConfig || !pMediaType || !parpmtMedia || !parCaps) | |
2004 return E_POINTER; | |
2005 | |
2006 hr=OLE_CALL_ARGS(pStreamConfig, GetNumberOfCapabilities, &count, &size); | |
2007 if (FAILED(hr)) { | |
2008 mp_msg(MSGT_TV, MSGL_DBG4, | |
2009 "tvi_dshow: Call to GetNumberOfCapabilities failed (get_available_formats_stream)\n"); | |
2010 return hr; | |
2011 } | |
2012 if (memcmp(pMediaType, &MEDIATYPE_Video, 16) == 0){ | |
2013 if (size != sizeof(VIDEO_STREAM_CONFIG_CAPS)) { | |
2014 mp_msg(MSGT_TV, MSGL_DBG4, | |
2015 "tvi_dshow: Wrong video structure size for GetNumberOfCapabilities (get_available_formats_stream)\n"); | |
2016 return E_FAIL; | |
2017 } else if (memcmp(pMediaType, &MEDIATYPE_Audio, 16) == 0){ | |
2018 if (size != sizeof(AUDIO_STREAM_CONFIG_CAPS)) { | |
2019 mp_msg(MSGT_TV, MSGL_DBG4, | |
2020 "tvi_dshow: Wrong audio structure size for GetNumberOfCapabilities (get_available_formats_stream)\n"); | |
2021 return E_FAIL; | |
2022 } else { | |
2023 mp_msg(MSGT_TV, MSGL_ERR, MSGTR_TVI_DS_UnsupportedMediaType,"get_available_formats_stream"); | |
2024 return E_FAIL; | |
2025 } | |
2026 } | |
2027 } | |
2028 done = 0; | |
2029 | |
2030 arpmt = (AM_MEDIA_TYPE **) malloc((count + 1) * sizeof(AM_MEDIA_TYPE *)); | |
2031 if (arpmt) { | |
2032 memset(arpmt, 0, (count + 1) * sizeof(AM_MEDIA_TYPE *)); | |
2033 | |
2034 pBuf = (void **) malloc((count + 1) * sizeof(void *)); | |
2035 if (pBuf) { | |
25061
1f0eb7aa3206
Ignore video formats which are supported by device
voroshil
parents:
25060
diff
changeset
|
2036 int dst = 0; |
24744 | 2037 memset(pBuf, 0, (count + 1) * sizeof(void *)); |
2038 | |
2039 for (i = 0; i < count; i++) { | |
25061
1f0eb7aa3206
Ignore video formats which are supported by device
voroshil
parents:
25060
diff
changeset
|
2040 pBuf[dst] = malloc(size); |
1f0eb7aa3206
Ignore video formats which are supported by device
voroshil
parents:
25060
diff
changeset
|
2041 |
1f0eb7aa3206
Ignore video formats which are supported by device
voroshil
parents:
25060
diff
changeset
|
2042 if (!pBuf[dst]) |
24744 | 2043 break; |
2044 | |
2045 hr = OLE_CALL_ARGS(pStreamConfig, GetStreamCaps, i, | |
25061
1f0eb7aa3206
Ignore video formats which are supported by device
voroshil
parents:
25060
diff
changeset
|
2046 &(arpmt[dst]), pBuf[dst]); |
24744 | 2047 if (FAILED(hr)) |
2048 break; | |
25061
1f0eb7aa3206
Ignore video formats which are supported by device
voroshil
parents:
25060
diff
changeset
|
2049 if(!memcmp(&(arpmt[dst]->majortype), &MEDIATYPE_Video, 16) && !subtype2imgfmt(&(arpmt[dst]->subtype))) |
1f0eb7aa3206
Ignore video formats which are supported by device
voroshil
parents:
25060
diff
changeset
|
2050 { |
1f0eb7aa3206
Ignore video formats which are supported by device
voroshil
parents:
25060
diff
changeset
|
2051 DisplayMediaType("Skipping unsupported video format", arpmt[dst]); |
1f0eb7aa3206
Ignore video formats which are supported by device
voroshil
parents:
25060
diff
changeset
|
2052 DeleteMediaType(arpmt[dst]); |
1f0eb7aa3206
Ignore video formats which are supported by device
voroshil
parents:
25060
diff
changeset
|
2053 free(pBuf[dst]); |
1f0eb7aa3206
Ignore video formats which are supported by device
voroshil
parents:
25060
diff
changeset
|
2054 arpmt[dst]=NULL; |
1f0eb7aa3206
Ignore video formats which are supported by device
voroshil
parents:
25060
diff
changeset
|
2055 pBuf[dst]=NULL; |
1f0eb7aa3206
Ignore video formats which are supported by device
voroshil
parents:
25060
diff
changeset
|
2056 continue; |
1f0eb7aa3206
Ignore video formats which are supported by device
voroshil
parents:
25060
diff
changeset
|
2057 } |
1f0eb7aa3206
Ignore video formats which are supported by device
voroshil
parents:
25060
diff
changeset
|
2058 dst++; |
24744 | 2059 } |
2060 if (i == count) { | |
2061 *parpmtMedia = arpmt; | |
2062 *parCaps = pBuf; | |
2063 done = 1; | |
2064 } | |
2065 } | |
2066 } | |
2067 if (!done) { | |
2068 for (i = 0; i < count; i++) { | |
2069 if (pBuf && pBuf[i]) | |
2070 free(pBuf[i]); | |
2071 if (arpmt && arpmt[i]) | |
2072 DeleteMediaType(arpmt[i]); | |
2073 } | |
2074 if (pBuf) | |
2075 free(pBuf); | |
2076 if (arpmt) | |
2077 free(arpmt); | |
2078 if (hr != S_OK) { | |
2079 mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: Call to GetStreamCaps failed (get_available_formats_stream)\n"); | |
2080 return hr; | |
2081 } else | |
2082 return E_OUTOFMEMORY; | |
2083 } | |
2084 return S_OK; | |
2085 } | |
2086 | |
2087 /** | |
2088 * \brief returns allocates an array and store available media formats for given pin type to it | |
2089 * | |
2090 * \param pBuilder ICaptureGraphBuilder2 interface of graph builder | |
2091 * \param pFilter IBaseFilter interface of capture device | |
2092 * \param pMediaType media type for search (MEDIATYPE_Video or MEDIATYPE_Audio) | |
2093 * \param[out] parpmtMediaType address of variable that receives pointer to array | |
2094 * | |
2095 * \return S_OK success | |
2096 * \return E_POINTER one of given pointers is null | |
2097 * \return apropriate error code otherwise | |
2098 */ | |
2099 static HRESULT get_available_formats_pin(ICaptureGraphBuilder2 * pBuilder, | |
2100 IBaseFilter * pFilter, | |
2101 const GUID * pMediaType, | |
2102 AM_MEDIA_TYPE *** parpmtMedia, | |
2103 void ***parCaps) | |
2104 { | |
2105 IEnumMediaTypes *pEnum; | |
2106 IPin *pPin; | |
2107 int i, count, size; | |
2108 ULONG cFetched; | |
2109 AM_MEDIA_TYPE *pmt; | |
2110 HRESULT hr; | |
2111 void **pBuf; | |
2112 AM_MEDIA_TYPE **arpmt; //This will be real array | |
2113 int isvideo; | |
2114 VIDEO_STREAM_CONFIG_CAPS *pVideoCaps; | |
2115 AUDIO_STREAM_CONFIG_CAPS *pAudioCaps; | |
2116 int p1, p2, p3; | |
2117 | |
2118 mp_msg(MSGT_TV, MSGL_DBG4, | |
2119 "tvi_dshow: get_available_formats_pin called\n"); | |
2120 if (!pBuilder || !pFilter || !pMediaType || !parpmtMedia) | |
2121 return E_POINTER; | |
2122 | |
2123 hr = OLE_CALL_ARGS(pBuilder, FindPin, (IUnknown *) pFilter, | |
2124 PINDIR_OUTPUT, NULL, pMediaType, FALSE, 0, &pPin); | |
2125 if (FAILED(hr)) { | |
2126 mp_msg(MSGT_TV, MSGL_DBG4, | |
2127 "tvi_dshow: Call to FindPin failed (get_available_formats_pin)\n"); | |
2128 return hr; | |
2129 } | |
2130 if (memcmp(pMediaType, &MEDIATYPE_Video, 16) == 0) { | |
2131 isvideo = 1; | |
2132 size = sizeof(VIDEO_STREAM_CONFIG_CAPS); | |
2133 } else if (memcmp(pMediaType, &MEDIATYPE_Audio, 16) == 0) { | |
2134 isvideo = 0; | |
2135 size = sizeof(AUDIO_STREAM_CONFIG_CAPS); | |
2136 } else { | |
2137 mp_msg(MSGT_TV, MSGL_ERR, MSGTR_TVI_DS_UnsupportedMediaType,"get_available_formats_pin"); | |
2138 return E_FAIL; | |
2139 } | |
2140 | |
2141 hr = OLE_CALL_ARGS(pPin, EnumMediaTypes, &pEnum); | |
2142 OLE_RELEASE_SAFE(pPin); | |
2143 if (FAILED(hr)) { | |
2144 mp_msg(MSGT_TV, MSGL_DBG4, | |
2145 "tvi_dshow: Call to EnumMediaTypes failed (get_available_formats_pin)\n"); | |
2146 return hr; | |
2147 } | |
2148 for (i = 0; OLE_CALL_ARGS(pEnum, Next, 1, &pmt, &cFetched) == S_OK; i++) { | |
2149 if (!pmt) | |
2150 break; | |
2151 } | |
2152 OLE_CALL(pEnum,Reset); | |
2153 | |
2154 count = i; | |
2155 arpmt = | |
2156 (AM_MEDIA_TYPE **) malloc((count + 1) * sizeof(AM_MEDIA_TYPE *)); | |
2157 if (!arpmt) | |
2158 return E_OUTOFMEMORY; | |
2159 memset(arpmt, 0, (count + 1) * sizeof(AM_MEDIA_TYPE *)); | |
2160 | |
2161 for (i = 0; | |
2162 i < count | |
2163 && OLE_CALL_ARGS(pEnum, Next, 1, &(arpmt[i]), &cFetched) == S_OK; | |
2164 i++); | |
2165 | |
2166 OLE_RELEASE_SAFE(pEnum); | |
2167 | |
2168 | |
2169 pBuf = (void **) malloc((count + 1) * sizeof(void *)); | |
2170 if (!pBuf) { | |
2171 for (i = 0; i < count; i++) | |
2172 if (arpmt[i]) | |
2173 DeleteMediaType(arpmt[i]); | |
2174 free(arpmt); | |
2175 return E_OUTOFMEMORY; | |
2176 } | |
2177 memset(pBuf, 0, (count + 1) * sizeof(void *)); | |
2178 | |
2179 for (i = 0; i < count; i++) { | |
2180 pBuf[i] = malloc(size); | |
2181 if (!pBuf[i]) | |
2182 break; | |
2183 memset(pBuf[i], 0, size); | |
2184 | |
2185 if (isvideo) { | |
2186 pVideoCaps = (VIDEO_STREAM_CONFIG_CAPS *) pBuf[i]; | |
2187 extract_video_format(arpmt[i], NULL, &p1, &p2); | |
2188 pVideoCaps->MaxOutputSize.cx = pVideoCaps->MinOutputSize.cx = | |
2189 p1; | |
2190 pVideoCaps->MaxOutputSize.cy = pVideoCaps->MinOutputSize.cy = | |
2191 p2; | |
2192 } else { | |
2193 pAudioCaps = (AUDIO_STREAM_CONFIG_CAPS *) pBuf[i]; | |
2194 extract_audio_format(arpmt[i], &p1, &p2, &p3); | |
2195 pAudioCaps->MaximumSampleFrequency = | |
2196 pAudioCaps->MinimumSampleFrequency = p1; | |
2197 pAudioCaps->MaximumBitsPerSample = | |
2198 pAudioCaps->MinimumBitsPerSample = p2; | |
2199 pAudioCaps->MaximumChannels = pAudioCaps->MinimumChannels = p3; | |
2200 } | |
2201 | |
2202 } | |
2203 if (i != count) { | |
2204 for (i = 0; i < count; i++) { | |
2205 if (arpmt[i]) | |
2206 DeleteMediaType(arpmt[i]); | |
2207 if (pBuf[i]) | |
2208 free(pBuf[i]); | |
2209 } | |
2210 free(arpmt); | |
2211 free(pBuf); | |
2212 return E_OUTOFMEMORY; | |
2213 } | |
2214 *parpmtMedia = arpmt; | |
2215 *parCaps = pBuf; | |
2216 | |
2217 return S_OK; | |
2218 } | |
2219 | |
2220 /* | |
2221 *--------------------------------------------------------------------------------------- | |
2222 * | |
2223 * Public methods | |
2224 * | |
2225 *--------------------------------------------------------------------------------------- | |
2226 */ | |
2227 /** | |
2228 * \brief fills given buffer with audio data (usually one block) | |
2229 * | |
2230 * \param priv driver's private data structure | |
2231 * \param buffer buffer to store data to | |
2232 * \param len buffer's size in bytes (usually one block size) | |
2233 * | |
2234 * \return audio pts if audio present, 1 - otherwise | |
2235 */ | |
2236 static double grab_audio_frame(priv_t * priv, char *buffer, int len) | |
2237 { | |
2238 int bytes = 0; | |
2239 int i; | |
2240 double pts; | |
2241 grabber_ringbuffer_t *rb = priv->a_buf; | |
2242 grabber_ringbuffer_t *vrb = priv->v_buf; | |
2243 | |
2244 if (!rb || !rb->ringbuffer) | |
2245 return 1; | |
2246 | |
2247 if(vrb && vrb->tStart<0){ | |
2248 memset(buffer,0,len); | |
2249 return 0; | |
2250 } | |
2251 if(vrb && rb->tStart<0) | |
2252 rb->tStart=vrb->tStart; | |
2253 | |
2254 if (len < rb->blocksize) | |
2255 bytes = len; | |
2256 else | |
2257 bytes = rb->blocksize; | |
2258 | |
2259 mp_msg(MSGT_TV, MSGL_DBG3,"tvi_dshow: FillBuffer (audio) called. %d blocks in buffer, %d bytes requested\n", | |
2260 rb->count, len); | |
2261 if(!rb->count){ | |
2262 mp_msg(MSGT_TV,MSGL_DBG4,"tvi_dshow: waiting for frame\n"); | |
2263 for(i=0;i<1000 && !rb->count;i++) usec_sleep(1000); | |
2264 if(!rb->count){ | |
2265 mp_msg(MSGT_TV,MSGL_DBG4,"tvi_dshow: waiting timeout\n"); | |
2266 return 0; | |
2267 } | |
2268 mp_msg(MSGT_TV,MSGL_DBG4,"tvi_dshow: got frame!\n"); | |
2269 } | |
2270 | |
2271 EnterCriticalSection(rb->pMutex); | |
2272 pts=rb->dpts[rb->head]-rb->tStart; | |
2273 memcpy(buffer, rb->ringbuffer[rb->head], bytes); | |
2274 rb->head = (rb->head + 1) % rb->buffersize; | |
2275 rb->count--; | |
2276 LeaveCriticalSection(rb->pMutex); | |
2277 return pts; | |
2278 } | |
2279 | |
2280 /** | |
2281 * \brief returns audio frame size | |
2282 * | |
2283 * \param priv driver's private data structure | |
2284 * | |
2285 * \return audio block size if audio enabled and 1 - otherwise | |
2286 */ | |
2287 static int get_audio_framesize(priv_t * priv) | |
2288 { | |
2289 if (!priv->a_buf) | |
2290 return 1; //no audio | |
2291 mp_msg(MSGT_TV,MSGL_DBG3,"get_audio_framesize: %d\n",priv->a_buf->blocksize); | |
2292 return priv->a_buf->blocksize; | |
2293 } | |
2294 | |
2295 #ifdef HAVE_TV_TELETEXT | |
2296 static int vbi_get_props(priv_t* priv,tt_stream_props* ptsp) | |
2297 { | |
2298 if(!priv || !ptsp) | |
2299 return TVI_CONTROL_FALSE; | |
2300 | |
2301 //STUBS!!! | |
2302 ptsp->interlaced=0; | |
2303 ptsp->offset=256; | |
2304 | |
2305 ptsp->sampling_rate=27e6; | |
2306 ptsp->samples_per_line=720; | |
2307 | |
2308 ptsp->count[0]=16; | |
2309 ptsp->count[1]=16; | |
2310 //END STUBS!!! | |
2311 ptsp->bufsize = ptsp->samples_per_line * (ptsp->count[0] + ptsp->count[1]); | |
2312 | |
2313 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", | |
2314 ptsp->sampling_rate, | |
2315 ptsp->offset, | |
2316 ptsp->samples_per_line, | |
2317 ptsp->interlaced?"Yes":"No", | |
2318 ptsp->count[0], | |
2319 ptsp->count[1]); | |
2320 | |
2321 return TVI_CONTROL_TRUE; | |
2322 } | |
2323 | |
2324 static void vbi_grabber(priv_t* priv) | |
2325 { | |
2326 grabber_ringbuffer_t *rb = priv->vbi_buf; | |
2327 int i; | |
2328 unsigned char* buf; | |
2329 if (!rb || !rb->ringbuffer) | |
2330 return; | |
2331 | |
2332 buf=calloc(1,rb->blocksize); | |
2333 for(i=0; i<23 && rb->count; i++){ | |
2334 memcpy(buf,rb->ringbuffer[rb->head],rb->blocksize); | |
2335 teletext_control(priv->priv_vbi,TV_VBI_CONTROL_DECODE_PAGE,&buf); | |
2336 rb->head = (rb->head + 1) % rb->buffersize; | |
2337 rb->count--; | |
2338 } | |
2339 free(buf); | |
2340 } | |
2341 #endif //HAVE_TV_TELETEXT | |
2342 | |
2343 /** | |
2344 * \brief fills given buffer with video data (usually one frame) | |
2345 * | |
2346 * \param priv driver's private data structure | |
2347 * \param buffer buffer to store data to | |
2348 * \param len buffer's size in bytes (usually one frame size) | |
2349 * | |
2350 * \return frame size if video present, 0 - otherwise | |
2351 */ | |
2352 static double grab_video_frame(priv_t * priv, char *buffer, int len) | |
2353 { | |
2354 int bytes = 0; | |
2355 int i; | |
2356 double pts; | |
2357 grabber_ringbuffer_t *rb = priv->v_buf; | |
2358 | |
2359 if (!rb || !rb->ringbuffer) | |
2360 return 1; | |
2361 if (len < rb->blocksize) | |
2362 bytes = len; | |
2363 else | |
2364 bytes = rb->blocksize; | |
2365 | |
2366 mp_msg(MSGT_TV, MSGL_DBG3,"tvi_dshow: FillBuffer (video) called. %d blocks in buffer, %d bytes requested\n", | |
2367 rb->count, len); | |
2368 if(!rb->count){ | |
2369 mp_msg(MSGT_TV,MSGL_DBG4,"tvi_dshow: waiting for frame\n"); | |
2370 for(i=0;i<1000 && !rb->count;i++) usec_sleep(1000); | |
2371 if(!rb->count){ | |
2372 mp_msg(MSGT_TV,MSGL_DBG4,"tvi_dshow: waiting timeout\n"); | |
2373 return 0; | |
2374 } | |
2375 mp_msg(MSGT_TV,MSGL_DBG4,"tvi_dshow: got frame!\n"); | |
2376 } | |
2377 EnterCriticalSection(rb->pMutex); | |
2378 if(rb->tStart<0) | |
2379 rb->tStart=rb->dpts[rb->head]; | |
2380 pts=rb->dpts[rb->head]-rb->tStart; | |
2381 memcpy(buffer, rb->ringbuffer[rb->head], bytes); | |
2382 rb->head = (rb->head + 1) % rb->buffersize; | |
2383 rb->count--; | |
2384 LeaveCriticalSection(rb->pMutex); | |
2385 | |
2386 #ifdef HAVE_TV_TELETEXT | |
2387 vbi_grabber(priv); | |
2388 #endif | |
2389 return pts; | |
2390 } | |
2391 | |
2392 /** | |
2393 * \brief returns frame size | |
2394 * | |
2395 * \param priv driver's private data structure | |
2396 * | |
2397 * \return frame size if video present, 0 - otherwise | |
2398 */ | |
2399 static int get_video_framesize(priv_t * priv) | |
2400 { | |
2401 // if(!priv->pmtVideo) return 1; //no video | |
2402 // return(priv->pmtVideo->lSampleSize); | |
2403 if (!priv->v_buf) | |
2404 return 1; //no video | |
2405 mp_msg(MSGT_TV,MSGL_DBG3,"geT_video_framesize: %d\n",priv->v_buf->blocksize); | |
2406 return priv->v_buf->blocksize; | |
2407 } | |
2408 | |
2409 /** | |
2410 * \brief calculate audio buffer size | |
2411 * \param video_buf_size size of video buffer in bytes | |
2412 * \param video_bitrate video bit rate | |
2413 * \param audio_bitrate audio bit rate | |
2414 * \return audio buffer isze in bytes | |
2415 * | |
2416 * \remarks length of video buffer and resulted audio buffer calculated in | |
2417 * seconds will be the same. | |
2418 */ | |
2419 static inline int audio_buf_size_from_video(int video_buf_size, int video_bitrate, int audio_bitrate) | |
2420 { | |
2421 int audio_buf_size = audio_bitrate * (video_buf_size / video_bitrate); | |
2422 mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: Audio capture buffer: %d * %d / %d = %d\n", | |
2423 audio_bitrate,video_buf_size,video_bitrate,audio_buf_size); | |
2424 return audio_buf_size; | |
2425 } | |
2426 | |
2427 /** | |
25057
7d74c1a2c840
Move chains building code into separate routines.
voroshil
parents:
25054
diff
changeset
|
2428 * \brief build video stream chain in graph |
7d74c1a2c840
Move chains building code into separate routines.
voroshil
parents:
25054
diff
changeset
|
2429 * \param priv private data structure |
24744 | 2430 * |
25057
7d74c1a2c840
Move chains building code into separate routines.
voroshil
parents:
25054
diff
changeset
|
2431 * \return S_OK if chain was built successfully, apropriate error code otherwise |
7d74c1a2c840
Move chains building code into separate routines.
voroshil
parents:
25054
diff
changeset
|
2432 */ |
7d74c1a2c840
Move chains building code into separate routines.
voroshil
parents:
25054
diff
changeset
|
2433 static HRESULT build_video_chain(priv_t *priv) |
24744 | 2434 { |
2435 HRESULT hr; | |
2436 | |
25059 | 2437 if(priv->v_buf) |
2438 return S_OK; | |
2439 | |
24744 | 2440 if (priv->pVideoStreamConfig) { |
2441 hr = OLE_CALL_ARGS(priv->pVideoStreamConfig, SetFormat, priv->pmtVideo); | |
2442 if (FAILED(hr)) { | |
2443 mp_msg(MSGT_TV,MSGL_ERR,MSGTR_TVI_DS_UnableSelectVideoFormat, (unsigned int)hr); | |
2444 } | |
2445 } | |
2446 | |
2447 priv->v_buf=calloc(1,sizeof(grabber_ringbuffer_t)); | |
25058 | 2448 if(!priv->v_buf) |
2449 return E_OUTOFMEMORY; | |
24744 | 2450 |
2451 if (priv->tv_param->buffer_size >= 0) { | |
2452 priv->v_buf->buffersize = priv->tv_param->buffer_size; | |
2453 } else { | |
2454 priv->v_buf->buffersize = 16; | |
2455 } | |
2456 | |
2457 priv->v_buf->buffersize *= 1024 * 1024; | |
25063
29260745e4fa
Pass all available formats to chain building routine and
voroshil
parents:
25061
diff
changeset
|
2458 hr=build_sub_graph(priv, priv->pVideoFilter, priv->v_buf, priv->arpmtVideo, priv->pmtVideo, &PIN_CATEGORY_CAPTURE); |
24744 | 2459 if(FAILED(hr)){ |
2460 mp_msg(MSGT_TV, MSGL_ERR, MSGTR_TVI_DS_UnableBuildVideoSubGraph,(unsigned int)hr); | |
25057
7d74c1a2c840
Move chains building code into separate routines.
voroshil
parents:
25054
diff
changeset
|
2461 return hr; |
24744 | 2462 } |
25057
7d74c1a2c840
Move chains building code into separate routines.
voroshil
parents:
25054
diff
changeset
|
2463 return S_OK; |
7d74c1a2c840
Move chains building code into separate routines.
voroshil
parents:
25054
diff
changeset
|
2464 } |
7d74c1a2c840
Move chains building code into separate routines.
voroshil
parents:
25054
diff
changeset
|
2465 |
7d74c1a2c840
Move chains building code into separate routines.
voroshil
parents:
25054
diff
changeset
|
2466 /** |
7d74c1a2c840
Move chains building code into separate routines.
voroshil
parents:
25054
diff
changeset
|
2467 * \brief build audio stream chain in graph |
7d74c1a2c840
Move chains building code into separate routines.
voroshil
parents:
25054
diff
changeset
|
2468 * \param priv private data structure |
7d74c1a2c840
Move chains building code into separate routines.
voroshil
parents:
25054
diff
changeset
|
2469 * |
7d74c1a2c840
Move chains building code into separate routines.
voroshil
parents:
25054
diff
changeset
|
2470 * \return S_OK if chain was built successfully, apropriate error code otherwise |
7d74c1a2c840
Move chains building code into separate routines.
voroshil
parents:
25054
diff
changeset
|
2471 */ |
7d74c1a2c840
Move chains building code into separate routines.
voroshil
parents:
25054
diff
changeset
|
2472 static HRESULT build_audio_chain(priv_t *priv) |
7d74c1a2c840
Move chains building code into separate routines.
voroshil
parents:
25054
diff
changeset
|
2473 { |
7d74c1a2c840
Move chains building code into separate routines.
voroshil
parents:
25054
diff
changeset
|
2474 HRESULT hr; |
7d74c1a2c840
Move chains building code into separate routines.
voroshil
parents:
25054
diff
changeset
|
2475 |
25059 | 2476 if(priv->a_buf) |
2477 return S_OK; | |
2478 | |
25057
7d74c1a2c840
Move chains building code into separate routines.
voroshil
parents:
25054
diff
changeset
|
2479 if(priv->immediate_mode) |
7d74c1a2c840
Move chains building code into separate routines.
voroshil
parents:
25054
diff
changeset
|
2480 return S_OK; |
7d74c1a2c840
Move chains building code into separate routines.
voroshil
parents:
25054
diff
changeset
|
2481 |
7d74c1a2c840
Move chains building code into separate routines.
voroshil
parents:
25054
diff
changeset
|
2482 if (priv->pAudioStreamConfig) { |
7d74c1a2c840
Move chains building code into separate routines.
voroshil
parents:
25054
diff
changeset
|
2483 hr = OLE_CALL_ARGS(priv->pAudioStreamConfig, SetFormat, |
7d74c1a2c840
Move chains building code into separate routines.
voroshil
parents:
25054
diff
changeset
|
2484 priv->pmtAudio); |
7d74c1a2c840
Move chains building code into separate routines.
voroshil
parents:
25054
diff
changeset
|
2485 if (FAILED(hr)) { |
7d74c1a2c840
Move chains building code into separate routines.
voroshil
parents:
25054
diff
changeset
|
2486 mp_msg(MSGT_TV,MSGL_ERR,MSGTR_TVI_DS_UnableSelectAudioFormat, (unsigned int)hr); |
7d74c1a2c840
Move chains building code into separate routines.
voroshil
parents:
25054
diff
changeset
|
2487 } |
7d74c1a2c840
Move chains building code into separate routines.
voroshil
parents:
25054
diff
changeset
|
2488 } |
7d74c1a2c840
Move chains building code into separate routines.
voroshil
parents:
25054
diff
changeset
|
2489 |
7d74c1a2c840
Move chains building code into separate routines.
voroshil
parents:
25054
diff
changeset
|
2490 if(priv->pmtAudio){ |
24744 | 2491 priv->a_buf=calloc(1,sizeof(grabber_ringbuffer_t)); |
25058 | 2492 if(!priv->a_buf) |
2493 return E_OUTOFMEMORY; | |
24744 | 2494 |
2495 /* let the audio buffer be the same size (in seconds) than video one */ | |
2496 priv->a_buf->buffersize=audio_buf_size_from_video( | |
2497 priv->v_buf->buffersize, | |
2498 (((VIDEOINFOHEADER *) priv->pmtVideo->pbFormat)->dwBitRate), | |
2499 (((WAVEFORMATEX *) (priv->pmtAudio->pbFormat))->nAvgBytesPerSec)); | |
2500 | |
25063
29260745e4fa
Pass all available formats to chain building routine and
voroshil
parents:
25061
diff
changeset
|
2501 hr=build_sub_graph(priv, priv->pAudioFilter, priv->a_buf,priv->arpmtAudio,priv->pmtAudio,&PIN_CATEGORY_CAPTURE); |
24744 | 2502 if(FAILED(hr)){ |
2503 mp_msg(MSGT_TV, MSGL_ERR, MSGTR_TVI_DS_UnableBuildAudioSubGraph,(unsigned int)hr); | |
2504 return 0; | |
2505 } | |
2506 } | |
25057
7d74c1a2c840
Move chains building code into separate routines.
voroshil
parents:
25054
diff
changeset
|
2507 return S_OK; |
7d74c1a2c840
Move chains building code into separate routines.
voroshil
parents:
25054
diff
changeset
|
2508 } |
7d74c1a2c840
Move chains building code into separate routines.
voroshil
parents:
25054
diff
changeset
|
2509 |
7d74c1a2c840
Move chains building code into separate routines.
voroshil
parents:
25054
diff
changeset
|
2510 /** |
7d74c1a2c840
Move chains building code into separate routines.
voroshil
parents:
25054
diff
changeset
|
2511 * \brief build VBI stream chain in graph |
7d74c1a2c840
Move chains building code into separate routines.
voroshil
parents:
25054
diff
changeset
|
2512 * \param priv private data structure |
7d74c1a2c840
Move chains building code into separate routines.
voroshil
parents:
25054
diff
changeset
|
2513 * |
7d74c1a2c840
Move chains building code into separate routines.
voroshil
parents:
25054
diff
changeset
|
2514 * \return S_OK if chain was built successfully, apropriate error code otherwise |
7d74c1a2c840
Move chains building code into separate routines.
voroshil
parents:
25054
diff
changeset
|
2515 */ |
7d74c1a2c840
Move chains building code into separate routines.
voroshil
parents:
25054
diff
changeset
|
2516 static HRESULT build_vbi_chain(priv_t *priv) |
7d74c1a2c840
Move chains building code into separate routines.
voroshil
parents:
25054
diff
changeset
|
2517 { |
24744 | 2518 #ifdef HAVE_TV_TELETEXT |
25057
7d74c1a2c840
Move chains building code into separate routines.
voroshil
parents:
25054
diff
changeset
|
2519 HRESULT hr; |
25063
29260745e4fa
Pass all available formats to chain building routine and
voroshil
parents:
25061
diff
changeset
|
2520 AM_MEDIA_TYPE* arpmtVBI[2] = { priv->pmtVBI, NULL }; |
25057
7d74c1a2c840
Move chains building code into separate routines.
voroshil
parents:
25054
diff
changeset
|
2521 |
25059 | 2522 if(priv->vbi_buf) |
2523 return S_OK; | |
2524 | |
24744 | 2525 if(priv->tv_param->tdevice) |
2526 { | |
2527 priv->vbi_buf=calloc(1,sizeof(grabber_ringbuffer_t)); | |
25058 | 2528 if(!priv->vbi_buf) |
2529 return E_OUTOFMEMORY; | |
2530 | |
24744 | 2531 init_ringbuffer(priv->vbi_buf,24,priv->tsp.bufsize); |
2532 | |
2533 priv->pmtVBI=calloc(1,sizeof(AM_MEDIA_TYPE)); | |
2534 priv->pmtVBI->majortype=MEDIATYPE_VBI; | |
25063
29260745e4fa
Pass all available formats to chain building routine and
voroshil
parents:
25061
diff
changeset
|
2535 hr=build_sub_graph(priv, priv->pVideoFilter, priv->vbi_buf,arpmtVBI,NULL,&PIN_CATEGORY_VBI); |
24744 | 2536 if(FAILED(hr)){ |
2537 mp_msg(MSGT_TV, MSGL_ERR, MSGTR_TVI_DS_UnableBuildVBISubGraph,(unsigned int)hr); | |
2538 return 0; | |
2539 } | |
2540 } | |
2541 #endif | |
25057
7d74c1a2c840
Move chains building code into separate routines.
voroshil
parents:
25054
diff
changeset
|
2542 return S_OK; |
7d74c1a2c840
Move chains building code into separate routines.
voroshil
parents:
25054
diff
changeset
|
2543 } |
7d74c1a2c840
Move chains building code into separate routines.
voroshil
parents:
25054
diff
changeset
|
2544 |
7d74c1a2c840
Move chains building code into separate routines.
voroshil
parents:
25054
diff
changeset
|
2545 /** |
7d74c1a2c840
Move chains building code into separate routines.
voroshil
parents:
25054
diff
changeset
|
2546 * \brief playback/capture real start |
7d74c1a2c840
Move chains building code into separate routines.
voroshil
parents:
25054
diff
changeset
|
2547 * |
7d74c1a2c840
Move chains building code into separate routines.
voroshil
parents:
25054
diff
changeset
|
2548 * \param priv driver's private data structure |
7d74c1a2c840
Move chains building code into separate routines.
voroshil
parents:
25054
diff
changeset
|
2549 * |
7d74c1a2c840
Move chains building code into separate routines.
voroshil
parents:
25054
diff
changeset
|
2550 * \return 1 if success, 0 - otherwise |
7d74c1a2c840
Move chains building code into separate routines.
voroshil
parents:
25054
diff
changeset
|
2551 * |
7d74c1a2c840
Move chains building code into separate routines.
voroshil
parents:
25054
diff
changeset
|
2552 * TODO: move some code from init() here |
7d74c1a2c840
Move chains building code into separate routines.
voroshil
parents:
25054
diff
changeset
|
2553 */ |
7d74c1a2c840
Move chains building code into separate routines.
voroshil
parents:
25054
diff
changeset
|
2554 static int start(priv_t * priv) |
7d74c1a2c840
Move chains building code into separate routines.
voroshil
parents:
25054
diff
changeset
|
2555 { |
7d74c1a2c840
Move chains building code into separate routines.
voroshil
parents:
25054
diff
changeset
|
2556 HRESULT hr; |
7d74c1a2c840
Move chains building code into separate routines.
voroshil
parents:
25054
diff
changeset
|
2557 |
7d74c1a2c840
Move chains building code into separate routines.
voroshil
parents:
25054
diff
changeset
|
2558 hr = build_video_chain(priv); |
7d74c1a2c840
Move chains building code into separate routines.
voroshil
parents:
25054
diff
changeset
|
2559 if(FAILED(hr)) |
7d74c1a2c840
Move chains building code into separate routines.
voroshil
parents:
25054
diff
changeset
|
2560 return 0; |
7d74c1a2c840
Move chains building code into separate routines.
voroshil
parents:
25054
diff
changeset
|
2561 |
7d74c1a2c840
Move chains building code into separate routines.
voroshil
parents:
25054
diff
changeset
|
2562 hr = build_audio_chain(priv); |
7d74c1a2c840
Move chains building code into separate routines.
voroshil
parents:
25054
diff
changeset
|
2563 if(FAILED(hr)) |
7d74c1a2c840
Move chains building code into separate routines.
voroshil
parents:
25054
diff
changeset
|
2564 return 0; |
7d74c1a2c840
Move chains building code into separate routines.
voroshil
parents:
25054
diff
changeset
|
2565 |
7d74c1a2c840
Move chains building code into separate routines.
voroshil
parents:
25054
diff
changeset
|
2566 hr = build_vbi_chain(priv); |
7d74c1a2c840
Move chains building code into separate routines.
voroshil
parents:
25054
diff
changeset
|
2567 if(FAILED(hr)) |
7d74c1a2c840
Move chains building code into separate routines.
voroshil
parents:
25054
diff
changeset
|
2568 return 0; |
7d74c1a2c840
Move chains building code into separate routines.
voroshil
parents:
25054
diff
changeset
|
2569 |
24744 | 2570 /* |
2571 Graph is ready to capture. Starting graph. | |
2572 */ | |
2573 if (mp_msg_test(MSGT_TV, MSGL_DBG2)) { | |
2574 mp_msg(MSGT_TV, MSGL_DBG2, "Debug pause 10sec\n"); | |
2575 usec_sleep(10000000); | |
2576 mp_msg(MSGT_TV, MSGL_DBG2, "Debug pause end\n"); | |
2577 } | |
2578 if (!priv->pMediaControl) { | |
2579 mp_msg(MSGT_TV,MSGL_ERR,MSGTR_TVI_DS_UnableGetMediaControlInterface,(unsigned int)E_POINTER); | |
2580 return 0; | |
2581 } | |
2582 hr = OLE_CALL(priv->pMediaControl, Run); | |
2583 if (FAILED(hr)) { | |
2584 mp_msg(MSGT_TV,MSGL_ERR,MSGTR_TVI_DS_UnableStartGraph, (unsigned int)hr); | |
2585 return 0; | |
2586 } | |
2587 mp_msg(MSGT_TV, MSGL_DBG2, "tvi_dshow: Graph is started.\n"); | |
2588 priv->state = 1; | |
2589 | |
2590 return (1); | |
2591 } | |
2592 | |
2593 /** | |
2594 * \brief driver initialization | |
2595 * | |
2596 * \param priv driver's private data structure | |
2597 * | |
2598 * \return 1 if success, 0 - otherwise | |
2599 */ | |
2600 static int init(priv_t * priv) | |
2601 { | |
2602 HRESULT hr; | |
2603 int result = 0; | |
2604 long lInput, lTunerInput; | |
2605 IEnumFilters *pEnum; | |
2606 IBaseFilter *pFilter; | |
2607 IPin *pVPOutPin; | |
2608 | |
2609 priv->state=0; | |
2610 CoInitialize(NULL); | |
2611 do{ | |
2612 hr = CoCreateInstance((GUID *) & CLSID_FilterGraph, NULL, | |
2613 CLSCTX_INPROC_SERVER, &IID_IGraphBuilder, | |
2614 (void **) &priv->pGraph); | |
2615 if(FAILED(hr)){ | |
2616 mp_msg(MSGT_TV,MSGL_DBG2, "tvi_dshow: CoCreateInstance(FilterGraph) call failed. Error:0x%x\n", (unsigned int)hr); | |
2617 break; | |
2618 } | |
2619 //Debug | |
2620 if (mp_msg_test(MSGT_TV, MSGL_DBG2)) { | |
2621 AddToRot((IUnknown *) priv->pGraph, &(priv->dwRegister)); | |
2622 } | |
2623 | |
2624 hr = CoCreateInstance((GUID *) & CLSID_CaptureGraphBuilder2, NULL, | |
2625 CLSCTX_INPROC_SERVER, &IID_ICaptureGraphBuilder2, | |
2626 (void **) &priv->pBuilder); | |
2627 if(FAILED(hr)){ | |
2628 mp_msg(MSGT_TV,MSGL_DBG2, "tvi_dshow: CoCreateInstance(CaptureGraphBuilder) call failed. Error:0x%x\n", (unsigned int)hr); | |
2629 break; | |
2630 } | |
2631 | |
2632 hr = OLE_CALL_ARGS(priv->pBuilder, SetFiltergraph, priv->pGraph); | |
2633 if(FAILED(hr)){ | |
2634 mp_msg(MSGT_TV,MSGL_ERR, "tvi_dshow: SetFiltergraph call failed. Error:0x%x\n",(unsigned int)hr); | |
2635 break; | |
2636 } | |
2637 | |
2638 mp_msg(MSGT_TV, MSGL_DBG2, "tvi_dshow: Searching for available video capture devices\n"); | |
2639 priv->pVideoFilter = find_capture_device(priv->dev_index, &CLSID_VideoInputDeviceCategory); | |
2640 if(!priv->pVideoFilter){ | |
2641 mp_msg(MSGT_TV,MSGL_ERR, MSGTR_TVI_DS_NoVideoCaptureDevice); | |
2642 break; | |
2643 } | |
2644 hr = OLE_CALL_ARGS(priv->pGraph, AddFilter, priv->pVideoFilter, NULL); | |
2645 if(FAILED(hr)){ | |
2646 mp_msg(MSGT_TV, MSGL_DBG2, "tvi_dshow: Unable to add video capture device to Directshow graph. Error:0x%x\n", (unsigned int)hr); | |
2647 break; | |
2648 } | |
2649 mp_msg(MSGT_TV, MSGL_DBG2, "tvi_dshow: Searching for available audio capture devices\n"); | |
2650 if (priv->adev_index != -1) { | |
2651 priv->pAudioFilter = find_capture_device(priv->adev_index, &CLSID_AudioInputDeviceCategory); //output available audio edevices | |
2652 if(!priv->pAudioFilter){ | |
2653 mp_msg(MSGT_TV,MSGL_ERR, MSGTR_TVI_DS_NoAudioCaptureDevice); | |
2654 break; | |
2655 } | |
2656 | |
2657 hr = OLE_CALL_ARGS(priv->pGraph, AddFilter, priv->pAudioFilter, NULL); | |
2658 if(FAILED(hr)){ | |
2659 mp_msg(MSGT_TV,MSGL_DBG2, "tvi_dshow: Unable to add audio capture device to Directshow graph. Error:0x%x\n", (unsigned int)hr); | |
2660 break; | |
2661 } | |
2662 } else | |
2663 hr = OLE_QUERYINTERFACE(priv->pVideoFilter, IID_IBaseFilter, priv->pAudioFilter); | |
2664 | |
2665 hr = OLE_QUERYINTERFACE(priv->pVideoFilter, IID_IAMVideoProcAmp,priv->pVideoProcAmp); | |
2666 if (FAILED(hr) && hr != E_NOINTERFACE) | |
2667 mp_msg(MSGT_TV, MSGL_DBG2, "tvi_dshow: Get IID_IAMVideoProcAmp failed (0x%x).\n", (unsigned int)hr); | |
2668 | |
2669 if (hr != S_OK) { | |
2670 mp_msg(MSGT_TV, MSGL_INFO, MSGTR_TVI_DS_VideoAdjustigNotSupported); | |
2671 priv->pVideoProcAmp = NULL; | |
2672 } | |
2673 | |
2674 hr = OLE_CALL_ARGS(priv->pBuilder, FindInterface, | |
2675 &PIN_CATEGORY_CAPTURE, | |
2676 &MEDIATYPE_Video, | |
2677 priv->pVideoFilter, | |
2678 &IID_IAMCrossbar, (void **) &(priv->pCrossbar)); | |
2679 if (FAILED(hr)) { | |
2680 mp_msg(MSGT_TV, MSGL_INFO, MSGTR_TVI_DS_SelectingInputNotSupported); | |
2681 priv->pCrossbar = NULL; | |
2682 } | |
2683 | |
2684 hr = OLE_CALL_ARGS(priv->pBuilder, FindInterface, | |
2685 &PIN_CATEGORY_CAPTURE, | |
2686 &MEDIATYPE_Video, | |
2687 priv->pVideoFilter, | |
2688 &IID_IAMStreamConfig, | |
2689 (void **) &(priv->pVideoStreamConfig)); | |
2690 if (FAILED(hr)) { | |
2691 mp_msg(MSGT_TV, MSGL_INFO, MSGTR_TVI_DS_ChangingWidthHeightNotSupported); | |
2692 priv->pVideoStreamConfig = NULL; | |
2693 } | |
2694 | |
2695 hr = OLE_CALL_ARGS(priv->pBuilder, FindInterface, | |
2696 &PIN_CATEGORY_CAPTURE, | |
2697 &MEDIATYPE_Audio, | |
2698 priv->pAudioFilter, | |
2699 &IID_IAMStreamConfig, | |
2700 (void **) &(priv->pAudioStreamConfig)); | |
2701 if (FAILED(hr)) { | |
2702 mp_msg(MSGT_TV, MSGL_DBG2, "tvi_dshow: Get IAMStreamConfig(audio) failed (0x%x).\n", (unsigned int)hr); | |
2703 priv->pAudioStreamConfig = NULL; | |
2704 } | |
2705 | |
2706 if (priv->tv_param->amode >= 0) { | |
2707 IAMTVAudio *pTVAudio; | |
2708 hr = OLE_CALL_ARGS(priv->pBuilder, FindInterface, NULL, NULL,priv->pVideoFilter,&IID_IAMTVAudio, (void *) &pTVAudio); | |
2709 if (hr == S_OK) { | |
2710 switch (priv->tv_param->amode) { | |
2711 case 0: | |
2712 hr = OLE_CALL_ARGS(pTVAudio, put_TVAudioMode, AMTVAUDIO_MODE_MONO); | |
2713 break; | |
2714 case 1: | |
2715 hr = OLE_CALL_ARGS(pTVAudio, put_TVAudioMode, AMTVAUDIO_MODE_STEREO); | |
2716 break; | |
2717 case 2: | |
2718 hr = OLE_CALL_ARGS(pTVAudio, put_TVAudioMode, | |
2719 AMTVAUDIO_MODE_LANG_A); | |
2720 break; | |
2721 case 3: | |
2722 hr = OLE_CALL_ARGS(pTVAudio, put_TVAudioMode, | |
2723 AMTVAUDIO_MODE_LANG_B); | |
2724 break; | |
2725 } | |
2726 OLE_RELEASE_SAFE(pTVAudio); | |
2727 if (FAILED(hr)) | |
2728 mp_msg(MSGT_TV, MSGL_WARN, MSGTR_TVI_DS_UnableSetAudioMode, priv->tv_param->amode,(unsigned int)hr); | |
2729 } | |
2730 } | |
2731 /* | |
2732 Getting available video formats (last pointer in array will be NULL) | |
2733 First tryin to call IAMStreamConfig::GetStreamCaos. this will give us additional information such as | |
2734 min/max picture dimensions, etc. If this call fails trying IPIn::EnumMediaTypes with default | |
2735 min/max values. | |
2736 */ | |
2737 | |
2738 hr = get_available_formats_stream(priv->pVideoStreamConfig, | |
2739 &MEDIATYPE_Video, | |
2740 &(priv->arpmtVideo), | |
2741 (void ***) &(priv->arVideoCaps)); | |
2742 if (FAILED(hr)) { | |
2743 mp_msg(MSGT_TV, MSGL_DBG2, "Unable to use IAMStreamConfig for retriving available video formats (Error:0x%x). Using EnumMediaTypes instead\n", (unsigned int)hr); | |
2744 hr = get_available_formats_pin(priv->pBuilder, priv->pVideoFilter, | |
2745 &MEDIATYPE_Video, | |
2746 &(priv->arpmtVideo), | |
2747 (void ***) &(priv->arVideoCaps)); | |
2748 if(FAILED(hr)){ | |
2749 mp_msg(MSGT_TV,MSGL_ERR, MSGTR_TVI_DS_UnableGetsupportedVideoFormats, (unsigned int)hr); | |
2750 break; | |
2751 } | |
2752 } | |
2753 priv->nVideoFormatUsed = 0; | |
2754 | |
2755 if (!priv->arpmtVideo[priv->nVideoFormatUsed] | |
2756 || !extract_video_format(priv->arpmtVideo[priv->nVideoFormatUsed], | |
2757 &(priv->fcc), &(priv->width), | |
2758 &(priv->height))) { | |
2759 mp_msg(MSGT_TV, MSGL_ERR, MSGTR_TVI_DS_ErrorParsingVideoFormatStruct); | |
2760 break; | |
2761 } | |
2762 priv->pmtVideo = CreateMediaType(priv->arpmtVideo[priv->nVideoFormatUsed]); | |
2763 /* | |
2764 Getting available audio formats (last pointer in array will be NULL) | |
2765 */ | |
2766 hr = get_available_formats_stream(priv->pAudioStreamConfig, | |
2767 &MEDIATYPE_Audio, | |
2768 &(priv->arpmtAudio), | |
2769 (void ***) &(priv->arAudioCaps)); | |
2770 if (FAILED(hr)) { | |
2771 mp_msg(MSGT_TV, MSGL_DBG2, "Unable to use IAMStreamConfig for retriving available audio formats (Error:0x%x). Using EnumMediaTypes instead\n", (unsigned int)hr); | |
2772 hr = get_available_formats_pin(priv->pBuilder, priv->pAudioFilter, | |
2773 &MEDIATYPE_Audio, | |
2774 &(priv->arpmtAudio), | |
2775 (void ***) &(priv->arAudioCaps)); | |
2776 if (FAILED(hr)) { | |
2777 mp_msg(MSGT_TV,MSGL_WARN, MSGTR_TVI_DS_UnableGetsupportedAudioFormats, (unsigned int)hr); | |
2778 /* | |
2779 Following combination will disable sound | |
2780 */ | |
2781 priv->arpmtAudio = (AM_MEDIA_TYPE **) malloc(sizeof(AM_MEDIA_TYPE *)); | |
2782 priv->arpmtAudio[0] = NULL; | |
2783 priv->pmtAudio = NULL; | |
2784 priv->pAudioStreamConfig = NULL; | |
2785 } | |
2786 } | |
2787 /* debug */ | |
2788 { | |
2789 int i; | |
2790 for (i = 0; priv->arpmtVideo[i]; i++) { | |
2791 DisplayMediaType("Available video format", priv->arpmtVideo[i]); | |
2792 } | |
2793 for (i = 0; priv->arpmtAudio[i]; i++) { | |
2794 DisplayMediaType("Available audio format", priv->arpmtAudio[i]); | |
2795 } | |
2796 } | |
2797 priv->nAudioFormatUsed = 0; | |
2798 if (priv->arpmtAudio[priv->nAudioFormatUsed]) { | |
2799 priv->pmtAudio = CreateMediaType(priv->arpmtAudio[priv->nAudioFormatUsed]); | |
2800 if (!extract_audio_format(priv->pmtAudio, &(priv->samplerate), NULL, NULL)) { | |
2801 mp_msg(MSGT_TV, MSGL_ERR, MSGTR_TVI_DS_ErrorParsingAudioFormatStruct); | |
2802 DisplayMediaType("audio format failed",priv->arpmtAudio[priv->nAudioFormatUsed]); | |
2803 break; | |
2804 } | |
2805 } | |
2806 show_filter_info(priv->pVideoFilter); | |
2807 | |
2808 hr = OLE_QUERYINTERFACE(priv->pGraph, IID_IMediaControl,priv->pMediaControl); | |
2809 if(FAILED(hr)){ | |
2810 mp_msg(MSGT_TV,MSGL_ERR, MSGTR_TVI_DS_UnableGetMediaControlInterface,(unsigned int)hr); | |
2811 break; | |
2812 } | |
2813 hr = OLE_CALL_ARGS(priv->pBuilder, FindInterface, | |
2814 &PIN_CATEGORY_CAPTURE, NULL, | |
2815 priv->pVideoFilter, | |
2816 &IID_IAMTVTuner, (void **) &(priv->pTVTuner)); | |
2817 | |
2818 if (!priv->pTVTuner) { | |
2819 mp_msg(MSGT_TV, MSGL_DBG2, "tvi_dshow: Unable to access IAMTVTuner (0x%x)\n", (unsigned int)hr); | |
2820 } | |
2821 | |
2822 // shows Tuner capabilities | |
2823 get_capabilities(priv); | |
2824 | |
2825 if (priv->pTVTuner) { | |
2826 hr = OLE_CALL_ARGS(priv->pTVTuner, put_CountryCode, | |
2827 chanlist2country(priv->tv_param->chanlist)); | |
2828 if(FAILED(hr)){ | |
2829 mp_msg(MSGT_TV,MSGL_DBG2, "tvi_dshow: Call to put_CountryCode failed. Error:0x%x\n",(unsigned int)hr); | |
2830 } | |
2831 | |
2832 hr = OLE_CALL_ARGS(priv->pTVTuner, put_Mode, AMTUNER_MODE_TV); | |
2833 if(FAILED(hr)){ | |
2834 mp_msg(MSGT_TV,MSGL_DBG2, "tvi_dshow: Call to put_Mode failed. Error:0x%x\n",(unsigned int)hr); | |
2835 break; | |
2836 } | |
2837 | |
2838 hr = OLE_CALL_ARGS(priv->pTVTuner, get_ConnectInput, &lInput); | |
2839 if(FAILED(hr)){ | |
2840 mp_msg(MSGT_TV,MSGL_DBG2, "tvi_dshow: Call to get_ConnectInput failed. Error:0x%x\n",(unsigned int)hr); | |
2841 break; | |
2842 } | |
2843 | |
2844 /* small hack */ | |
2845 lTunerInput = strstr(priv->tv_param->chanlist, "cable") ? TunerInputCable : TunerInputAntenna; | |
2846 | |
2847 hr = OLE_CALL_ARGS(priv->pTVTuner, put_InputType, lInput, lTunerInput); | |
2848 if(FAILED(hr)){ | |
2849 mp_msg(MSGT_TV,MSGL_DBG2, "tvi_dshow: Call to put_InputType failed. Error:0x%x\n",(unsigned int)hr); | |
2850 break; | |
2851 } | |
2852 | |
2853 } | |
2854 | |
2855 /** | |
2856 for VIVO cards we should check if preview pin is available on video capture device. | |
2857 If it is not, we have to connect Video Port Manager filter to VP pin of capture device filter. | |
2858 Otherwise we will get 0x8007001f (Device is not functioning properly) when attempting to start graph | |
2859 */ | |
2860 hr = OLE_CALL_ARGS(priv->pBuilder, FindPin, | |
2861 (IUnknown *) priv->pVideoFilter, | |
2862 PINDIR_OUTPUT, | |
2863 &PIN_CATEGORY_VIDEOPORT, NULL, FALSE, | |
2864 0, (IPin **) & pVPOutPin); | |
2865 if (SUCCEEDED(hr)) { | |
2866 hr = OLE_CALL_ARGS(priv->pGraph, Render, pVPOutPin); | |
2867 OLE_RELEASE_SAFE(pVPOutPin); | |
2868 | |
2869 if (FAILED(hr)) { | |
2870 mp_msg(MSGT_TV,MSGL_ERR, MSGTR_TVI_DS_UnableTerminateVPPin, (unsigned int)hr); | |
2871 break; | |
2872 } | |
2873 } | |
2874 | |
2875 OLE_CALL_ARGS(priv->pGraph, EnumFilters, &pEnum); | |
2876 while (OLE_CALL_ARGS(pEnum, Next, 1, &pFilter, NULL) == S_OK) { | |
2877 LPVIDEOWINDOW pVideoWindow; | |
2878 hr = OLE_QUERYINTERFACE(pFilter, IID_IVideoWindow, pVideoWindow); | |
2879 if (SUCCEEDED(hr)) | |
2880 { | |
2881 if(priv->tv_param->hidden_vp_renderer){ | |
2882 OLE_CALL_ARGS(pVideoWindow,put_Visible,/* OAFALSE*/ 0); | |
2883 OLE_CALL_ARGS(pVideoWindow,put_AutoShow,/* OAFALSE*/ 0); | |
2884 }else | |
2885 { | |
2886 OLE_CALL_ARGS(priv->pGraph, RemoveFilter, pFilter); | |
2887 } | |
2888 OLE_RELEASE_SAFE(pVideoWindow); | |
2889 } | |
2890 OLE_RELEASE_SAFE(pFilter); | |
2891 } | |
2892 OLE_RELEASE_SAFE(pEnum); | |
2893 if(priv->tv_param->system_clock) | |
2894 { | |
2895 LPREFERENCECLOCK rc; | |
2896 IBaseFilter* pBF; | |
2897 hr = CoCreateInstance((GUID *) & CLSID_SystemClock, NULL, | |
2898 CLSCTX_INPROC_SERVER, &IID_IReferenceClock, | |
2899 (void *) &rc); | |
2900 | |
2901 OLE_QUERYINTERFACE(priv->pBuilder,IID_IBaseFilter,pBF); | |
2902 OLE_CALL_ARGS(pBF,SetSyncSource,rc); | |
2903 } | |
2904 #ifdef HAVE_TV_TELETEXT | |
2905 if(vbi_get_props(priv,&(priv->tsp))!=TVI_CONTROL_TRUE) | |
2906 break; | |
2907 #endif | |
2908 result = 1; | |
2909 } while(0); | |
2910 | |
2911 if (!result){ | |
2912 mp_msg(MSGT_TV,MSGL_ERR, MSGTR_TVI_DS_GraphInitFailure); | |
2913 uninit(priv); | |
2914 } | |
2915 return result; | |
2916 } | |
2917 | |
2918 /** | |
2919 * \brief driver uninitialization | |
2920 * | |
2921 * \param priv driver's private data structure | |
2922 * | |
2923 * \return always 1 | |
2924 */ | |
2925 static int uninit(priv_t * priv) | |
2926 { | |
2927 int i; | |
2928 if (!priv) | |
2929 return (1); | |
2930 //Debug | |
2931 if (priv->dwRegister) { | |
2932 RemoveFromRot(priv->dwRegister); | |
2933 } | |
2934 #ifdef HAVE_TV_TELETEXT | |
2935 teletext_control(priv->priv_vbi,TV_VBI_CONTROL_STOP,(void*)1); | |
2936 #endif | |
2937 //stop audio grabber thread | |
2938 | |
2939 if (priv->state && priv->pMediaControl) { | |
2940 OLE_CALL(priv->pMediaControl, Stop); | |
2941 } | |
2942 OLE_RELEASE_SAFE(priv->pMediaControl); | |
2943 priv->state = 0; | |
2944 | |
2945 if (priv->pGraph) { | |
2946 if (priv->pVideoFilter) | |
2947 OLE_CALL_ARGS(priv->pGraph, RemoveFilter, priv->pVideoFilter); | |
2948 if (priv->pAudioFilter) | |
2949 OLE_CALL_ARGS(priv->pGraph, RemoveFilter, priv->pAudioFilter); | |
2950 } | |
2951 OLE_RELEASE_SAFE(priv->pCrossbar); | |
2952 OLE_RELEASE_SAFE(priv->pVideoStreamConfig); | |
2953 OLE_RELEASE_SAFE(priv->pAudioStreamConfig); | |
2954 OLE_RELEASE_SAFE(priv->pVideoProcAmp); | |
2955 OLE_RELEASE_SAFE(priv->pVideoFilter); | |
2956 OLE_RELEASE_SAFE(priv->pAudioFilter); | |
2957 OLE_RELEASE_SAFE(priv->pGraph); | |
2958 OLE_RELEASE_SAFE(priv->pBuilder); | |
2959 OLE_RELEASE_SAFE(priv->pCSGCB); | |
2960 | |
2961 if (priv->pmtVideo) | |
2962 DeleteMediaType(priv->pmtVideo); | |
2963 if (priv->pmtAudio) | |
2964 DeleteMediaType(priv->pmtAudio); | |
2965 if (priv->pmtVBI) | |
2966 DeleteMediaType(priv->pmtVBI); | |
2967 | |
2968 if (priv->arpmtVideo) { | |
2969 for (i = 0; priv->arpmtVideo[i]; i++) { | |
2970 DeleteMediaType(priv->arpmtVideo[i]); | |
2971 } | |
2972 free(priv->arpmtVideo); | |
2973 } | |
2974 if (priv->arVideoCaps) { | |
2975 for (i = 0; priv->arVideoCaps[i]; i++) { | |
2976 free(priv->arVideoCaps[i]); | |
2977 } | |
2978 free(priv->arVideoCaps); | |
2979 } | |
2980 if (priv->arpmtAudio) { | |
2981 for (i = 0; priv->arpmtAudio[i]; i++) { | |
2982 DeleteMediaType(priv->arpmtAudio[i]); | |
2983 } | |
2984 free(priv->arpmtAudio); | |
2985 } | |
2986 if (priv->arAudioCaps) { | |
2987 for (i = 0; priv->arAudioCaps[i]; i++) { | |
2988 free(priv->arAudioCaps[i]); | |
2989 } | |
2990 free(priv->arAudioCaps); | |
2991 } | |
2992 if (priv->a_buf) { | |
2993 destroy_ringbuffer(priv->a_buf); | |
2994 free(priv->a_buf); | |
2995 priv->a_buf = NULL; | |
2996 } | |
2997 if (priv->v_buf) { | |
2998 destroy_ringbuffer(priv->v_buf); | |
2999 free(priv->v_buf); | |
3000 priv->v_buf = NULL; | |
3001 } | |
3002 if (priv->vbi_buf) { | |
3003 destroy_ringbuffer(priv->vbi_buf); | |
3004 free(priv->vbi_buf); | |
3005 priv->vbi_buf = NULL; | |
3006 } | |
3007 if(priv->freq_table){ | |
3008 priv->freq_table_len=-1; | |
3009 free(priv->freq_table); | |
3010 priv->freq_table=NULL; | |
3011 } | |
3012 CoUninitialize(); | |
3013 return (1); | |
3014 } | |
3015 | |
3016 /** | |
3017 * \brief driver pre-initialization | |
3018 * | |
3019 * \param device string, containing device name in form "x[.y]", where x is video capture device | |
3020 * (default: 0, first available); y (if given) sets audio capture device | |
3021 * | |
3022 * \return 1 if success,0 - otherwise | |
3023 */ | |
3024 static tvi_handle_t *tvi_init_dshow(tv_param_t* tv_param) | |
3025 { | |
3026 tvi_handle_t *h; | |
3027 priv_t *priv; | |
3028 int a; | |
3029 | |
3030 h = new_handle(); | |
3031 if (!h) | |
3032 return (NULL); | |
3033 | |
3034 priv = h->priv; | |
3035 | |
3036 memset(priv, 0, sizeof(priv_t)); | |
3037 priv->direct_setfreq_call = 1; //first using direct call. if it fails, workaround will be enabled | |
3038 priv->direct_getfreq_call = 1; //first using direct call. if it fails, workaround will be enabled | |
3039 priv->adev_index = -1; | |
3040 priv->freq_table_len=-1; | |
3041 priv->tv_param=tv_param; | |
3042 | |
3043 if (tv_param->device) { | |
3044 if (sscanf(tv_param->device, "%d", &a) == 1) { | |
3045 priv->dev_index = a; | |
3046 } else { | |
3047 mp_msg(MSGT_TV, MSGL_ERR, MSGTR_TVI_DS_WrongDeviceParam, tv_param->device); | |
3048 free_handle(h); | |
3049 return NULL; | |
3050 } | |
3051 if (priv->dev_index < 0) { | |
3052 mp_msg(MSGT_TV, MSGL_ERR, MSGTR_TVI_DS_WrongDeviceIndex, a); | |
3053 free_handle(h); | |
3054 return NULL; | |
3055 } | |
3056 } | |
3057 if (tv_param->adevice) { | |
3058 if (sscanf(tv_param->adevice, "%d", &a) == 1) { | |
3059 priv->adev_index = a; | |
3060 } else { | |
3061 mp_msg(MSGT_TV, MSGL_ERR, MSGTR_TVI_DS_WrongADeviceParam, tv_param->adevice); | |
3062 free_handle(h); | |
3063 return NULL; | |
3064 } | |
3065 if (priv->dev_index < 0) { | |
3066 mp_msg(MSGT_TV, MSGL_ERR, MSGTR_TVI_DS_WrongADeviceIndex, a); | |
3067 free_handle(h); | |
3068 return NULL; | |
3069 } | |
3070 } | |
3071 return h; | |
3072 } | |
3073 | |
3074 /** | |
3075 * \brief driver's ioctl handler | |
3076 * | |
3077 * \param priv driver's private data structure | |
3078 * \param cmd ioctl command | |
3079 * \param arg ioct command's parameter | |
3080 * | |
3081 * \return TVI_CONTROL_TRUE if success | |
3082 * \return TVI_CONTROL_FALSE if failure | |
3083 * \return TVI_CONTROL_UNKNOWN if unknowm cmd called | |
3084 */ | |
3085 static int control(priv_t * priv, int cmd, void *arg) | |
3086 { | |
3087 switch (cmd) { | |
3088 /* need rewrite */ | |
3089 case TVI_CONTROL_VID_SET_FORMAT: | |
3090 { | |
3091 int fcc, i; | |
25063
29260745e4fa
Pass all available formats to chain building routine and
voroshil
parents:
25061
diff
changeset
|
3092 void* tmp; |
25068
4b14d188ed34
Add all passed to VID_SET_FORMAT formats to the end of
voroshil
parents:
25067
diff
changeset
|
3093 int result = TVI_CONTROL_TRUE; |
25063
29260745e4fa
Pass all available formats to chain building routine and
voroshil
parents:
25061
diff
changeset
|
3094 |
24744 | 3095 if (priv->state) |
3096 return TVI_CONTROL_FALSE; | |
3097 fcc = *(int *) arg; | |
3098 | |
3099 if(!priv->arpmtVideo) | |
3100 return TVI_CONTROL_FALSE; | |
3101 for (i = 0; priv->arpmtVideo[i]; i++) | |
3102 if (check_video_format | |
3103 (priv->arpmtVideo[i], fcc, priv->width, priv->height)) | |
3104 break; | |
3105 if (!priv->arpmtVideo[i]) | |
25068
4b14d188ed34
Add all passed to VID_SET_FORMAT formats to the end of
voroshil
parents:
25067
diff
changeset
|
3106 { |
4b14d188ed34
Add all passed to VID_SET_FORMAT formats to the end of
voroshil
parents:
25067
diff
changeset
|
3107 int fps = 0; |
4b14d188ed34
Add all passed to VID_SET_FORMAT formats to the end of
voroshil
parents:
25067
diff
changeset
|
3108 VIDEOINFOHEADER* Vhdr = NULL; |
4b14d188ed34
Add all passed to VID_SET_FORMAT formats to the end of
voroshil
parents:
25067
diff
changeset
|
3109 AM_MEDIA_TYPE *pmt; |
4b14d188ed34
Add all passed to VID_SET_FORMAT formats to the end of
voroshil
parents:
25067
diff
changeset
|
3110 |
4b14d188ed34
Add all passed to VID_SET_FORMAT formats to the end of
voroshil
parents:
25067
diff
changeset
|
3111 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)); |
4b14d188ed34
Add all passed to VID_SET_FORMAT formats to the end of
voroshil
parents:
25067
diff
changeset
|
3112 |
4b14d188ed34
Add all passed to VID_SET_FORMAT formats to the end of
voroshil
parents:
25067
diff
changeset
|
3113 if (priv->arpmtVideo[0]) |
4b14d188ed34
Add all passed to VID_SET_FORMAT formats to the end of
voroshil
parents:
25067
diff
changeset
|
3114 Vhdr = (VIDEOINFOHEADER *) priv->arpmtVideo[0]->pbFormat; |
4b14d188ed34
Add all passed to VID_SET_FORMAT formats to the end of
voroshil
parents:
25067
diff
changeset
|
3115 |
4b14d188ed34
Add all passed to VID_SET_FORMAT formats to the end of
voroshil
parents:
25067
diff
changeset
|
3116 if(Vhdr && Vhdr->bmiHeader.biSizeImage) |
4b14d188ed34
Add all passed to VID_SET_FORMAT formats to the end of
voroshil
parents:
25067
diff
changeset
|
3117 fps = Vhdr->dwBitRate / (8 * Vhdr->bmiHeader.biSizeImage); |
4b14d188ed34
Add all passed to VID_SET_FORMAT formats to the end of
voroshil
parents:
25067
diff
changeset
|
3118 |
4b14d188ed34
Add all passed to VID_SET_FORMAT formats to the end of
voroshil
parents:
25067
diff
changeset
|
3119 pmt=create_video_format(fcc, priv->width, priv->height, fps); |
4b14d188ed34
Add all passed to VID_SET_FORMAT formats to the end of
voroshil
parents:
25067
diff
changeset
|
3120 if(!pmt) |
4b14d188ed34
Add all passed to VID_SET_FORMAT formats to the end of
voroshil
parents:
25067
diff
changeset
|
3121 { |
4b14d188ed34
Add all passed to VID_SET_FORMAT formats to the end of
voroshil
parents:
25067
diff
changeset
|
3122 mp_msg(MSGT_TV, MSGL_V, "tvi_dshow: Unable to create AM_MEDIA_TYPE structure for given format\n"); |
4b14d188ed34
Add all passed to VID_SET_FORMAT formats to the end of
voroshil
parents:
25067
diff
changeset
|
3123 return TVI_CONTROL_FALSE; |
4b14d188ed34
Add all passed to VID_SET_FORMAT formats to the end of
voroshil
parents:
25067
diff
changeset
|
3124 } |
4b14d188ed34
Add all passed to VID_SET_FORMAT formats to the end of
voroshil
parents:
25067
diff
changeset
|
3125 priv->arpmtVideo=realloc(priv->arpmtVideo, (i+2)*sizeof(AM_MEDIA_TYPE*)); |
4b14d188ed34
Add all passed to VID_SET_FORMAT formats to the end of
voroshil
parents:
25067
diff
changeset
|
3126 priv->arpmtVideo[i+1] = NULL; |
4b14d188ed34
Add all passed to VID_SET_FORMAT formats to the end of
voroshil
parents:
25067
diff
changeset
|
3127 priv->arpmtVideo[i] = pmt; |
4b14d188ed34
Add all passed to VID_SET_FORMAT formats to the end of
voroshil
parents:
25067
diff
changeset
|
3128 |
4b14d188ed34
Add all passed to VID_SET_FORMAT formats to the end of
voroshil
parents:
25067
diff
changeset
|
3129 result = TVI_CONTROL_FALSE; |
4b14d188ed34
Add all passed to VID_SET_FORMAT formats to the end of
voroshil
parents:
25067
diff
changeset
|
3130 } |
24744 | 3131 |
25063
29260745e4fa
Pass all available formats to chain building routine and
voroshil
parents:
25061
diff
changeset
|
3132 tmp = priv->arpmtVideo[0]; |
29260745e4fa
Pass all available formats to chain building routine and
voroshil
parents:
25061
diff
changeset
|
3133 priv->arpmtVideo[0] = priv->arpmtVideo[i]; |
29260745e4fa
Pass all available formats to chain building routine and
voroshil
parents:
25061
diff
changeset
|
3134 priv->arpmtVideo[i] = tmp; |
29260745e4fa
Pass all available formats to chain building routine and
voroshil
parents:
25061
diff
changeset
|
3135 |
29260745e4fa
Pass all available formats to chain building routine and
voroshil
parents:
25061
diff
changeset
|
3136 tmp = priv->arVideoCaps[0]; |
29260745e4fa
Pass all available formats to chain building routine and
voroshil
parents:
25061
diff
changeset
|
3137 priv->arVideoCaps[0] = priv->arVideoCaps[i]; |
29260745e4fa
Pass all available formats to chain building routine and
voroshil
parents:
25061
diff
changeset
|
3138 priv->arVideoCaps[i] = tmp; |
29260745e4fa
Pass all available formats to chain building routine and
voroshil
parents:
25061
diff
changeset
|
3139 |
29260745e4fa
Pass all available formats to chain building routine and
voroshil
parents:
25061
diff
changeset
|
3140 priv->nVideoFormatUsed = 0; |
24744 | 3141 |
3142 if (priv->pmtVideo) | |
3143 DeleteMediaType(priv->pmtVideo); | |
3144 priv->pmtVideo = | |
3145 CreateMediaType(priv->arpmtVideo[priv->nVideoFormatUsed]); | |
3146 DisplayMediaType("VID_SET_FORMAT", priv->pmtVideo); | |
3147 /* | |
3148 Setting width & height to preferred by driver values | |
3149 */ | |
3150 extract_video_format(priv->arpmtVideo[priv->nVideoFormatUsed], | |
3151 &(priv->fcc), &(priv->width), | |
3152 &(priv->height)); | |
25068
4b14d188ed34
Add all passed to VID_SET_FORMAT formats to the end of
voroshil
parents:
25067
diff
changeset
|
3153 return result; |
24744 | 3154 } |
3155 case TVI_CONTROL_VID_GET_FORMAT: | |
3156 { | |
3157 if(!priv->pmtVideo) | |
3158 return TVI_CONTROL_FALSE; | |
25067
5abe2c29b7d8
Ensure that when VID_GET_FORMAT ioctl is called,
voroshil
parents:
25066
diff
changeset
|
3159 /* |
5abe2c29b7d8
Ensure that when VID_GET_FORMAT ioctl is called,
voroshil
parents:
25066
diff
changeset
|
3160 Build video chain (for video format negotiation). |
5abe2c29b7d8
Ensure that when VID_GET_FORMAT ioctl is called,
voroshil
parents:
25066
diff
changeset
|
3161 If this was done before, routine will do nothing. |
5abe2c29b7d8
Ensure that when VID_GET_FORMAT ioctl is called,
voroshil
parents:
25066
diff
changeset
|
3162 */ |
5abe2c29b7d8
Ensure that when VID_GET_FORMAT ioctl is called,
voroshil
parents:
25066
diff
changeset
|
3163 build_video_chain(priv); |
24744 | 3164 DisplayMediaType("VID_GET_FORMAT", priv->pmtVideo); |
3165 if (priv->fcc) { | |
3166 *(int *) arg = priv->fcc; | |
3167 return (TVI_CONTROL_TRUE); | |
3168 } else | |
3169 return (TVI_CONTROL_FALSE); | |
3170 } | |
3171 case TVI_CONTROL_VID_SET_WIDTH: | |
3172 { | |
3173 VIDEO_STREAM_CONFIG_CAPS *pCaps; | |
3174 VIDEOINFOHEADER *Vhdr; | |
3175 int width = *(int *) arg; | |
3176 if (priv->state) | |
3177 return TVI_CONTROL_FALSE; | |
3178 | |
3179 pCaps = priv->arVideoCaps[priv->nVideoFormatUsed]; | |
3180 if (!pCaps) | |
3181 return TVI_CONTROL_FALSE; | |
3182 if (width < pCaps->MinOutputSize.cx | |
3183 || width > pCaps->MaxOutputSize.cx) | |
3184 return TVI_CONTROL_FALSE; | |
3185 | |
3186 if (width % pCaps->OutputGranularityX) | |
3187 return TVI_CONTROL_FALSE; | |
3188 | |
3189 if (!priv->pmtVideo || !priv->pmtVideo->pbFormat) | |
3190 return TVI_CONTROL_FALSE; | |
3191 Vhdr = (VIDEOINFOHEADER *) priv->pmtVideo->pbFormat; | |
3192 Vhdr->bmiHeader.biWidth = width; | |
3193 priv->pmtVideo->lSampleSize = Vhdr->bmiHeader.biSizeImage = | |
3194 labs(Vhdr->bmiHeader.biBitCount * Vhdr->bmiHeader.biWidth * | |
3195 Vhdr->bmiHeader.biHeight) >> 3; | |
3196 | |
3197 priv->width = width; | |
3198 | |
3199 return (TVI_CONTROL_TRUE); | |
3200 } | |
3201 case TVI_CONTROL_VID_GET_WIDTH: | |
3202 { | |
3203 if (priv->width) { | |
3204 *(int *) arg = priv->width; | |
3205 return (TVI_CONTROL_TRUE); | |
3206 } else | |
3207 return TVI_CONTROL_FALSE; | |
3208 } | |
3209 case TVI_CONTROL_VID_CHK_WIDTH: | |
3210 { | |
3211 VIDEO_STREAM_CONFIG_CAPS *pCaps; | |
3212 int width = *(int *) arg; | |
3213 pCaps = priv->arVideoCaps[priv->nVideoFormatUsed]; | |
3214 if (!pCaps) | |
3215 return TVI_CONTROL_FALSE; | |
3216 if (width < pCaps->MinOutputSize.cx | |
3217 || width > pCaps->MaxOutputSize.cx) | |
3218 return TVI_CONTROL_FALSE; | |
3219 | |
3220 if (width % pCaps->OutputGranularityX) | |
3221 return TVI_CONTROL_FALSE; | |
3222 return (TVI_CONTROL_TRUE); | |
3223 } | |
3224 case TVI_CONTROL_VID_SET_HEIGHT: | |
3225 { | |
3226 VIDEO_STREAM_CONFIG_CAPS *pCaps; | |
3227 VIDEOINFOHEADER *Vhdr; | |
3228 int height = *(int *) arg; | |
3229 if (priv->state) | |
3230 return TVI_CONTROL_FALSE; | |
3231 | |
3232 pCaps = priv->arVideoCaps[priv->nVideoFormatUsed]; | |
3233 if (!pCaps) | |
3234 return TVI_CONTROL_FALSE; | |
3235 if (height < pCaps->MinOutputSize.cy | |
3236 || height > pCaps->MaxOutputSize.cy) | |
3237 return TVI_CONTROL_FALSE; | |
3238 | |
3239 if (height % pCaps->OutputGranularityY) | |
3240 return TVI_CONTROL_FALSE; | |
3241 | |
3242 if (!priv->pmtVideo || !priv->pmtVideo->pbFormat) | |
3243 return TVI_CONTROL_FALSE; | |
3244 Vhdr = (VIDEOINFOHEADER *) priv->pmtVideo->pbFormat; | |
3245 | |
3246 if (Vhdr->bmiHeader.biHeight < 0) | |
3247 Vhdr->bmiHeader.biHeight = -height; | |
3248 else | |
3249 Vhdr->bmiHeader.biHeight = height; | |
3250 priv->pmtVideo->lSampleSize = Vhdr->bmiHeader.biSizeImage = | |
3251 labs(Vhdr->bmiHeader.biBitCount * Vhdr->bmiHeader.biWidth * | |
3252 Vhdr->bmiHeader.biHeight) >> 3; | |
3253 | |
3254 priv->height = height; | |
3255 return (TVI_CONTROL_TRUE); | |
3256 } | |
3257 case TVI_CONTROL_VID_GET_HEIGHT: | |
3258 { | |
3259 if (priv->height) { | |
3260 *(int *) arg = priv->height; | |
3261 return (TVI_CONTROL_TRUE); | |
3262 } else | |
3263 return TVI_CONTROL_FALSE; | |
3264 } | |
3265 case TVI_CONTROL_VID_CHK_HEIGHT: | |
3266 { | |
3267 VIDEO_STREAM_CONFIG_CAPS *pCaps; | |
3268 int height = *(int *) arg; | |
3269 pCaps = priv->arVideoCaps[priv->nVideoFormatUsed]; | |
3270 if (!pCaps) | |
3271 return TVI_CONTROL_FALSE; | |
3272 if (height < pCaps->MinOutputSize.cy | |
3273 || height > pCaps->MaxOutputSize.cy) | |
3274 return TVI_CONTROL_FALSE; | |
3275 | |
3276 if (height % pCaps->OutputGranularityY) | |
3277 return TVI_CONTROL_FALSE; | |
3278 | |
3279 return (TVI_CONTROL_TRUE); | |
3280 } | |
3281 case TVI_CONTROL_IS_AUDIO: | |
3282 if (!priv->pmtAudio) | |
3283 return TVI_CONTROL_FALSE; | |
3284 else | |
3285 return TVI_CONTROL_TRUE; | |
3286 case TVI_CONTROL_IS_VIDEO: | |
3287 return TVI_CONTROL_TRUE; | |
3288 case TVI_CONTROL_AUD_GET_FORMAT: | |
3289 { | |
3290 *(int *) arg = AF_FORMAT_S16_LE; | |
3291 if (!priv->pmtAudio) | |
3292 return TVI_CONTROL_FALSE; | |
3293 else | |
3294 return TVI_CONTROL_TRUE; | |
3295 } | |
3296 case TVI_CONTROL_AUD_GET_CHANNELS: | |
3297 { | |
3298 *(int *) arg = priv->channels; | |
3299 if (!priv->pmtAudio) | |
3300 return TVI_CONTROL_FALSE; | |
3301 else | |
3302 return TVI_CONTROL_TRUE; | |
3303 } | |
3304 case TVI_CONTROL_AUD_SET_SAMPLERATE: | |
3305 { | |
3306 int i, samplerate; | |
3307 if (priv->state) | |
3308 return TVI_CONTROL_FALSE; | |
3309 if (!priv->arpmtAudio[0]) | |
3310 return TVI_CONTROL_FALSE; | |
3311 | |
3312 samplerate = *(int *) arg;; | |
3313 | |
3314 for (i = 0; priv->arpmtAudio[i]; i++) | |
3315 if (check_audio_format | |
3316 (priv->arpmtAudio[i], samplerate, 16, priv->channels)) | |
3317 break; | |
3318 if (!priv->arpmtAudio[i]) { | |
3319 //request not found. failing back to first available | |
3320 mp_msg(MSGT_TV, MSGL_WARN, MSGTR_TVI_DS_SamplerateNotsupported, samplerate); | |
3321 i = 0; | |
3322 } | |
3323 if (priv->pmtAudio) | |
3324 DeleteMediaType(priv->pmtAudio); | |
3325 priv->pmtAudio = CreateMediaType(priv->arpmtAudio[i]); | |
3326 extract_audio_format(priv->arpmtAudio[i], &(priv->samplerate), | |
3327 NULL, &(priv->channels)); | |
3328 return TVI_CONTROL_TRUE; | |
3329 } | |
3330 case TVI_CONTROL_AUD_GET_SAMPLERATE: | |
3331 { | |
3332 *(int *) arg = priv->samplerate; | |
3333 if (!priv->samplerate) | |
3334 return TVI_CONTROL_FALSE; | |
3335 if (!priv->pmtAudio) | |
3336 return TVI_CONTROL_FALSE; | |
3337 else | |
3338 return TVI_CONTROL_TRUE; | |
3339 } | |
3340 case TVI_CONTROL_AUD_GET_SAMPLESIZE: | |
3341 { | |
3342 WAVEFORMATEX *pWF; | |
3343 if (!priv->pmtAudio) | |
3344 return TVI_CONTROL_FALSE; | |
3345 if (!priv->pmtAudio->pbFormat) | |
3346 return TVI_CONTROL_FALSE; | |
3347 pWF = (WAVEFORMATEX *) priv->pmtAudio->pbFormat; | |
3348 *(int *) arg = pWF->wBitsPerSample / 8; | |
3349 return TVI_CONTROL_TRUE; | |
3350 } | |
3351 case TVI_CONTROL_IS_TUNER: | |
3352 { | |
3353 if (!priv->pTVTuner) | |
3354 return TVI_CONTROL_FALSE; | |
3355 | |
3356 return (TVI_CONTROL_TRUE); | |
3357 } | |
3358 case TVI_CONTROL_TUN_SET_NORM: | |
3359 { | |
3360 IAMAnalogVideoDecoder *pVD; | |
3361 long lAnalogFormat; | |
3362 int i; | |
3363 HRESULT hr; | |
3364 | |
3365 i = *(int *) arg; | |
3366 i--; | |
3367 if (i < 0 || i >= tv_available_norms_count) | |
3368 return TVI_CONTROL_FALSE; | |
3369 lAnalogFormat = tv_norms[tv_available_norms[i]].index; | |
3370 | |
3371 hr = OLE_QUERYINTERFACE(priv->pVideoFilter,IID_IAMAnalogVideoDecoder, pVD); | |
3372 if (hr != S_OK) | |
3373 return TVI_CONTROL_FALSE; | |
3374 hr = OLE_CALL_ARGS(pVD, get_TVFormat, &lAnalogFormat); | |
3375 OLE_RELEASE_SAFE(pVD); | |
3376 if (FAILED(hr)) | |
3377 return (TVI_CONTROL_FALSE); | |
3378 else | |
3379 return (TVI_CONTROL_TRUE); | |
3380 } | |
3381 case TVI_CONTROL_TUN_GET_NORM: | |
3382 { | |
3383 long lAnalogFormat; | |
3384 int i; | |
3385 HRESULT hr; | |
3386 IAMAnalogVideoDecoder *pVD; | |
3387 | |
3388 hr = OLE_QUERYINTERFACE(priv->pVideoFilter,IID_IAMAnalogVideoDecoder, pVD); | |
3389 if (hr == S_OK) { | |
3390 hr = OLE_CALL_ARGS(pVD, get_TVFormat, &lAnalogFormat); | |
3391 OLE_RELEASE_SAFE(pVD); | |
3392 } | |
3393 | |
3394 if (FAILED(hr)) { //trying another method | |
3395 if (!priv->pTVTuner) | |
3396 return TVI_CONTROL_FALSE; | |
3397 hr=OLE_CALL_ARGS(priv->pTVTuner, get_TVFormat, &lAnalogFormat); | |
3398 if (FAILED(hr)) | |
3399 return TVI_CONTROL_FALSE; | |
3400 } | |
3401 for (i = 0; i < tv_available_norms_count; i++) { | |
3402 if (tv_norms[tv_available_norms[i]].index == lAnalogFormat) { | |
3403 *(int *) arg = i + 1; | |
3404 return TVI_CONTROL_TRUE; | |
3405 } | |
3406 } | |
3407 return (TVI_CONTROL_FALSE); | |
3408 } | |
3409 case TVI_CONTROL_SPC_GET_NORMID: | |
3410 { | |
3411 int i; | |
3412 if (!priv->pTVTuner) | |
3413 return TVI_CONTROL_FALSE; | |
3414 for (i = 0; i < tv_available_norms_count; i++) { | |
3415 if (!strcasecmp | |
3416 (tv_norms[tv_available_norms[i]].name, (char *) arg)) { | |
3417 *(int *) arg = i + 1; | |
3418 return TVI_CONTROL_TRUE; | |
3419 } | |
3420 } | |
3421 return TVI_CONTROL_FALSE; | |
3422 } | |
3423 case TVI_CONTROL_SPC_SET_INPUT: | |
3424 { | |
3425 return set_crossbar_input(priv, *(int *) arg); | |
3426 } | |
3427 case TVI_CONTROL_TUN_GET_FREQ: | |
3428 { | |
3429 unsigned long lFreq; | |
3430 int ret; | |
3431 if (!priv->pTVTuner) | |
3432 return TVI_CONTROL_FALSE; | |
3433 | |
3434 ret = get_frequency(priv, &lFreq); | |
3435 lFreq = lFreq * 16 / 1000000; //convert from Hz to 1/16 MHz units | |
3436 | |
3437 *(unsigned long *) arg = lFreq; | |
3438 return ret; | |
3439 } | |
3440 case TVI_CONTROL_TUN_SET_FREQ: | |
3441 { | |
3442 unsigned long nFreq = *(unsigned long *) arg; | |
3443 if (!priv->pTVTuner) | |
3444 return TVI_CONTROL_FALSE; | |
3445 //convert to Hz | |
3446 nFreq = 1000000 * nFreq / 16; //convert from 1/16 MHz units to Hz | |
3447 return set_frequency(priv, nFreq); | |
3448 } | |
3449 case TVI_CONTROL_VID_SET_HUE: | |
3450 return set_control(priv, VideoProcAmp_Hue, *(int *) arg); | |
3451 case TVI_CONTROL_VID_GET_HUE: | |
3452 return get_control(priv, VideoProcAmp_Hue, (int *) arg); | |
3453 case TVI_CONTROL_VID_SET_CONTRAST: | |
3454 return set_control(priv, VideoProcAmp_Contrast, *(int *) arg); | |
3455 case TVI_CONTROL_VID_GET_CONTRAST: | |
3456 return get_control(priv, VideoProcAmp_Contrast, (int *) arg); | |
3457 case TVI_CONTROL_VID_SET_SATURATION: | |
3458 return set_control(priv, VideoProcAmp_Saturation, *(int *) arg); | |
3459 case TVI_CONTROL_VID_GET_SATURATION: | |
3460 return get_control(priv, VideoProcAmp_Saturation, (int *) arg); | |
3461 case TVI_CONTROL_VID_SET_BRIGHTNESS: | |
3462 return set_control(priv, VideoProcAmp_Brightness, *(int *) arg); | |
3463 case TVI_CONTROL_VID_GET_BRIGHTNESS: | |
3464 return get_control(priv, VideoProcAmp_Brightness, (int *) arg); | |
3465 | |
3466 case TVI_CONTROL_VID_GET_FPS: | |
3467 { | |
3468 VIDEOINFOHEADER *Vhdr; | |
3469 if (!priv->pmtVideo) | |
3470 return TVI_CONTROL_FALSE; | |
3471 if (!priv->pmtVideo->pbFormat) | |
3472 return TVI_CONTROL_FALSE; | |
3473 Vhdr = (VIDEOINFOHEADER *) priv->pmtVideo->pbFormat; | |
3474 *(float *) arg = | |
25028
2cae9470f53b
Fix FPS from bitrate calculation (was 8 times larger than real value).
voroshil
parents:
25019
diff
changeset
|
3475 (1.0 * Vhdr->dwBitRate) / (Vhdr->bmiHeader.biSizeImage * 8); |
24744 | 3476 return TVI_CONTROL_TRUE; |
3477 } | |
3478 case TVI_CONTROL_IMMEDIATE: | |
3479 priv->immediate_mode = 1; | |
3480 return TVI_CONTROL_TRUE; | |
3481 #ifdef HAVE_TV_TELETEXT | |
3482 case TVI_CONTROL_VBI_INIT: | |
3483 { | |
3484 void* ptr; | |
3485 ptr=&(priv->tsp); | |
3486 if(teletext_control(NULL,TV_VBI_CONTROL_START,&ptr)==TVI_CONTROL_TRUE) | |
3487 priv->priv_vbi=ptr; | |
3488 else | |
3489 priv->priv_vbi=NULL; | |
3490 return TVI_CONTROL_TRUE; | |
3491 } | |
3492 default: | |
3493 return teletext_control(priv->priv_vbi,cmd,arg); | |
3494 #endif | |
3495 } | |
3496 return (TVI_CONTROL_UNKNOWN); | |
3497 } |