Mercurial > mplayer.hg
annotate libmpdemux/tvi_v4l.c @ 2836:ec672ea5ac2c
Applied SAMI patch by Evgeny Chukreev <codedj at echo dot ru>
author | atmos4 |
---|---|
date | Sun, 11 Nov 2001 15:41:17 +0000 |
parents | 596a6ba3520f |
children | c63562f5f56f |
rev | line source |
---|---|
2802 | 1 /* |
2 v4l interface for libmpemux/tvi | |
3 | |
4 (C) Alex Beregszaszi <alex@naxine.org> | |
5 | |
6 Some ideas are based on xawtv/libng's grab-v4l.c written by | |
7 Gerd Knorr <kraxel@bytesex.org> | |
8 | |
9 CODE IS UNDER DEVELOPMENT, NO FEATURE REQUESTS PLEASE! | |
10 */ | |
11 | |
2790 | 12 #include "config.h" |
13 | |
14 #ifdef USE_TV | |
15 | |
16 #include <stdio.h> | |
17 #include <errno.h> | |
18 #include <fcntl.h> | |
2802 | 19 #include <signal.h> |
2790 | 20 #include <sys/ioctl.h> |
21 #include <sys/types.h> | |
22 #include <linux/videodev.h> | |
23 #include <unistd.h> | |
24 #include <sys/mman.h> | |
25 | |
2830 | 26 #include "mp_msg.h" |
27 #include "../libao2/afmt.h" | |
28 #include "../libvo/img_format.h" | |
29 #include "../libvo/fastmemcpy.h" | |
30 | |
2790 | 31 #include "tv.h" |
32 | |
33 static tvi_info_t info = { | |
34 "Video for Linux TV Input", | |
35 "v4l", | |
2802 | 36 "Alex Beregszaszi <alex@naxine.org>", |
37 "under development" | |
38 }; | |
39 | |
2790 | 40 typedef struct { |
2802 | 41 /* general */ |
2790 | 42 char *video_device; |
43 int fd; | |
44 struct video_capability capability; | |
45 struct video_channel *channels; | |
46 struct video_tuner tuner; | |
2802 | 47 |
48 /* video */ | |
2790 | 49 struct video_picture picture; |
2802 | 50 int format; /* output format */ |
2790 | 51 int width; |
52 int height; | |
2802 | 53 int bytesperline; |
54 | |
55 struct video_mbuf mbuf; | |
56 unsigned char *mmap; | |
57 struct video_mmap *buf; | |
58 int nbuf; | |
59 int queue; | |
60 | |
61 /* audio */ | |
62 struct video_audio audio; | |
2790 | 63 } priv_t; |
64 | |
65 #include "tvi_def.h" | |
66 | |
67 static const char *device_cap[] = { | |
68 "capture", "tuner", "teletext", "overlay", "chromakey", "clipping", | |
2802 | 69 "frameram", "scales", "monochrome", "subcapture", "mpeg-decoder", |
70 "mpeg-encoder", "mjpeg-decoder", "mjpeg-encoder", NULL | |
71 }; | |
72 | |
73 static const char *device_pal[] = { | |
74 "-", "grey", "hi240", "rgb16", "rgb24", "rgb32", "rgb15", "yuv422", | |
75 "yuyv", "uyvy", "yuv420", "yuv411", "raw", "yuv422p", "yuv411p", | |
76 "yuv420p", "yuv410p", NULL | |
77 }; | |
78 #define PALETTE(x) ((x < sizeof(device_pal)/sizeof(char*)) ? device_pal[x] : "UNKNOWN") | |
79 | |
80 static int palette2depth(int palette) | |
81 { | |
2810 | 82 switch(palette) |
83 { | |
84 case VIDEO_PALETTE_RGB555: | |
85 return(15); | |
86 case VIDEO_PALETTE_RGB565: | |
87 return(16); | |
88 case VIDEO_PALETTE_RGB24: | |
89 return(24); | |
90 case VIDEO_PALETTE_RGB32: | |
91 return(32); | |
92 case VIDEO_PALETTE_YUV420P: | |
93 return(12); | |
94 case VIDEO_PALETTE_YUV422: | |
95 case VIDEO_PALETTE_UYVY: | |
96 return(16); | |
97 } | |
98 return(-1); | |
2802 | 99 } |
100 | |
101 static int format2palette(int format) | |
102 { | |
2810 | 103 switch(format) |
104 { | |
105 case IMGFMT_RGB15: | |
106 return(VIDEO_PALETTE_RGB555); | |
107 case IMGFMT_RGB16: | |
108 return(VIDEO_PALETTE_RGB565); | |
109 case IMGFMT_RGB24: | |
110 return(VIDEO_PALETTE_RGB24); | |
111 case IMGFMT_RGB32: | |
112 return(VIDEO_PALETTE_RGB32); | |
113 case IMGFMT_YV12: | |
114 return(VIDEO_PALETTE_YUV420P); | |
115 case IMGFMT_UYVY: | |
116 return(VIDEO_PALETTE_YUV422); | |
117 } | |
118 return(-1); | |
2802 | 119 } |
120 | |
121 #if 0 | |
122 struct STRTAB { | |
123 long nr; | |
124 const char *str; | |
125 }; | |
126 | |
127 static struct STRTAB stereo[] = { | |
128 { 0, "auto" }, | |
129 { VIDEO_SOUND_MONO, "mono" }, | |
130 { VIDEO_SOUND_STEREO, "stereo" }, | |
131 { VIDEO_SOUND_LANG1, "lang1" }, | |
132 { VIDEO_SOUND_LANG2, "lang1" }, | |
133 { -1, NULL } | |
134 }; | |
135 | |
136 static struct STRTAB norms_v4l[] = { | |
137 { VIDEO_MODE_PAL, "PAL" }, | |
138 { VIDEO_MODE_NTSC, "NTSC" }, | |
139 { VIDEO_MODE_SECAM, "SECAM" }, | |
140 { VIDEO_MODE_AUTO, "AUTO" }, | |
141 { -1, NULL } | |
142 }; | |
143 | |
144 static struct STRTAB norms_bttv[] = { | |
145 { VIDEO_MODE_PAL, "PAL" }, | |
146 { VIDEO_MODE_NTSC, "NTSC" }, | |
147 { VIDEO_MODE_SECAM, "SECAM" }, | |
148 { 3, "PAL-NC" }, | |
149 { 4, "PAL-M" }, | |
150 { 5, "PAL-N" }, | |
151 { 6, "NTSC-JP" }, | |
152 { -1, NULL } | |
2790 | 153 }; |
154 | |
2802 | 155 static unsigned short _format2palette[VIDEO_FMT_COUNT] = { |
156 0, /* unused */ | |
157 VIDEO_PALETTE_HI240, /* RGB8 */ | |
158 VIDEO_PALETTE_GREY, | |
159 VIDEO_PALETTE_RGB555, | |
160 VIDEO_PALETTE_RGB565, | |
161 0, | |
162 0, | |
163 VIDEO_PALETTE_RGB24, | |
164 VIDEO_PALETTE_RGB32, | |
165 0, | |
166 0, | |
167 0, | |
168 0, | |
169 VIDEO_PALETTE_YUV422, | |
170 VIDEO_PALETTE_YUV422P, | |
171 VIDEO_PALETTE_YUV420P, | |
172 }; | |
173 #define FMT2PAL(fmt) ((fmt < sizeof(format2palette)/sizeof(unsigned short)) ? \ | |
174 format2palette[fmt] : 0); | |
175 | |
176 const unsigned int vfmt_to_depth[] = { | |
177 0, | |
178 8, | |
179 8, | |
180 16, | |
181 16, | |
182 16, | |
183 16, | |
184 24, | |
185 32, | |
186 24, | |
187 32, | |
188 16, | |
189 32, | |
190 16, | |
191 16, | |
192 12, | |
193 0, | |
194 0, | |
195 }; | |
196 #endif | |
197 | |
198 static int one = 1, zero = 0; | |
199 | |
2790 | 200 tvi_handle_t *tvi_init_v4l(char *device) |
201 { | |
202 tvi_handle_t *h; | |
203 priv_t *priv; | |
204 | |
205 h = new_handle(); | |
206 if (!h) | |
207 return(NULL); | |
208 | |
209 priv = h->priv; | |
210 | |
2802 | 211 /* set video device name */ |
2790 | 212 if (!device) |
213 { | |
2819
2e58962dc9fe
cleaned up some warnings, and tv_param_on moved out from #ifdef USE_TV
alex
parents:
2818
diff
changeset
|
214 priv->video_device = (char *)malloc(strlen("/dev/video0")); |
2802 | 215 sprintf(priv->video_device, "/dev/video0"); |
2790 | 216 } |
217 else | |
218 { | |
2819
2e58962dc9fe
cleaned up some warnings, and tv_param_on moved out from #ifdef USE_TV
alex
parents:
2818
diff
changeset
|
219 priv->video_device = (char *)malloc(strlen(device)); |
2790 | 220 strcpy(priv->video_device, device); |
221 } | |
222 | |
223 return(h); | |
224 } | |
225 | |
2802 | 226 static int init(priv_t *priv, tvi_param_t *params) |
2790 | 227 { |
228 int i; | |
229 | |
2810 | 230 priv->fd = open(priv->video_device, O_RDWR); |
2790 | 231 if (priv->fd == -1) |
232 { | |
2818 | 233 mp_msg(MSGT_TV, MSGL_ERR, "unable to open '%s': %s\n", |
2802 | 234 priv->video_device, strerror(errno)); |
2790 | 235 goto err; |
236 } | |
237 | |
2818 | 238 mp_msg(MSGT_TV, MSGL_V, "Video fd: %d\n", priv->fd); |
2790 | 239 |
2802 | 240 /* get capabilities (priv->capability is needed!) */ |
2790 | 241 if (ioctl(priv->fd, VIDIOCGCAP, &priv->capability) == -1) |
242 { | |
2818 | 243 mp_msg(MSGT_TV, MSGL_ERR, "ioctl get capabilites failed: %s\n", strerror(errno)); |
2790 | 244 goto err; |
245 } | |
246 | |
247 fcntl(priv->fd, F_SETFD, FD_CLOEXEC); | |
2818 | 248 // siginit(); |
2802 | 249 |
250 #if 0 | |
251 for (i=0; params[i].opt; i++) | |
252 { | |
253 if (!strcmp(params[i].opt, "input")) | |
254 priv->input = (int)*(void **)params[i].value; | |
255 } | |
256 printf("priv->input: %d\n", priv->input); | |
257 #endif | |
258 | |
2818 | 259 mp_msg(MSGT_TV, MSGL_INFO, "Selected device: %s\n", priv->capability.name); |
260 mp_msg(MSGT_TV, MSGL_INFO, " Capabilites: "); | |
2790 | 261 for (i = 0; device_cap[i] != NULL; i++) |
262 if (priv->capability.type & (1 << i)) | |
2818 | 263 mp_msg(MSGT_TV, MSGL_INFO, "%s ", device_cap[i]); |
264 mp_msg(MSGT_TV, MSGL_INFO, "\n"); | |
265 mp_msg(MSGT_TV, MSGL_INFO, " Device type: %d\n", priv->capability.type); | |
266 mp_msg(MSGT_TV, MSGL_INFO, " Supported sizes: %dx%d => %dx%d\n", | |
2790 | 267 priv->capability.minwidth, priv->capability.minheight, |
268 priv->capability.maxwidth, priv->capability.maxheight); | |
269 priv->width = priv->capability.minwidth; | |
270 priv->height = priv->capability.minheight; | |
2818 | 271 mp_msg(MSGT_TV, MSGL_INFO, " Inputs: %d\n", priv->capability.channels); |
2790 | 272 |
2819
2e58962dc9fe
cleaned up some warnings, and tv_param_on moved out from #ifdef USE_TV
alex
parents:
2818
diff
changeset
|
273 priv->channels = (struct video_channel *)malloc(sizeof(struct video_channel)*priv->capability.channels); |
2790 | 274 memset(priv->channels, 0, sizeof(struct video_channel)*priv->capability.channels); |
275 for (i = 0; i < priv->capability.channels; i++) | |
276 { | |
277 priv->channels[i].channel = i; | |
278 ioctl(priv->fd, VIDIOCGCHAN, &priv->channels[i]); | |
2818 | 279 mp_msg(MSGT_TV, MSGL_INFO, " %d: %s: %s%s%s%s (tuner:%d, norm:%d)\n", i, |
2790 | 280 priv->channels[i].name, |
281 (priv->channels[i].flags & VIDEO_VC_TUNER) ? "tuner " : "", | |
282 (priv->channels[i].flags & VIDEO_VC_AUDIO) ? "audio " : "", | |
283 (priv->channels[i].flags & VIDEO_TYPE_TV) ? "tv " : "", | |
2802 | 284 (priv->channels[i].flags & VIDEO_TYPE_CAMERA) ? "camera " : "", |
285 priv->channels[i].tuners, | |
286 priv->channels[i].norm); | |
287 } | |
288 | |
289 if (!(priv->capability.type & VID_TYPE_CAPTURE)) | |
290 { | |
2818 | 291 mp_msg(MSGT_TV, MSGL_ERR, "Only grabbing supported (for overlay use another program)\n"); |
2802 | 292 goto err; |
293 } | |
294 | |
295 /* map grab buffer */ | |
296 if (ioctl(priv->fd, VIDIOCGMBUF, &priv->mbuf) == -1) | |
297 { | |
2818 | 298 mp_msg(MSGT_TV, MSGL_ERR, "ioctl get mbuf failed: %s\n", strerror(errno)); |
2802 | 299 goto err; |
2790 | 300 } |
301 | |
2818 | 302 mp_msg(MSGT_TV, MSGL_V, "mbuf: size=%d, frames=%d\n", |
2802 | 303 priv->mbuf.size, priv->mbuf.frames); |
304 priv->mmap = mmap(0, priv->mbuf.size, PROT_READ|PROT_WRITE, | |
305 MAP_SHARED, priv->fd, 0); | |
2819
2e58962dc9fe
cleaned up some warnings, and tv_param_on moved out from #ifdef USE_TV
alex
parents:
2818
diff
changeset
|
306 if (priv->mmap == (unsigned char *)-1) |
2802 | 307 { |
2818 | 308 mp_msg(MSGT_TV, MSGL_ERR, "Unabel to map memory for buffers: %s\n", strerror(errno)); |
2802 | 309 goto err; |
310 } | |
2818 | 311 mp_msg(MSGT_TV, MSGL_DBG2, "our buffer: %p\n", priv->mmap); |
2790 | 312 |
2802 | 313 /* num of buffers */ |
314 priv->nbuf = priv->mbuf.frames; | |
2790 | 315 |
2802 | 316 /* video buffers */ |
2819
2e58962dc9fe
cleaned up some warnings, and tv_param_on moved out from #ifdef USE_TV
alex
parents:
2818
diff
changeset
|
317 priv->buf = (struct video_mmap *)malloc(priv->nbuf * sizeof(struct video_mmap)); |
2802 | 318 memset(priv->buf, 0, priv->nbuf * sizeof(struct video_mmap)); |
2790 | 319 |
320 return(1); | |
321 | |
322 err: | |
323 if (priv->fd != -1) | |
324 close(priv->fd); | |
325 return(0); | |
326 } | |
327 | |
2802 | 328 static int uninit(priv_t *priv) |
2790 | 329 { |
2802 | 330 #warning "Implement uninit!" |
2790 | 331 } |
332 | |
2802 | 333 static int start(priv_t *priv) |
2790 | 334 { |
2802 | 335 int i; |
336 | |
337 | |
338 if (ioctl(priv->fd, VIDIOCGPICT, &priv->picture) == -1) | |
2790 | 339 { |
2818 | 340 mp_msg(MSGT_TV, MSGL_ERR, "ioctl get picture failed: %s\n", strerror(errno)); |
2802 | 341 return(0); |
2790 | 342 } |
343 | |
2802 | 344 priv->picture.palette = format2palette(priv->format); |
345 priv->picture.depth = palette2depth(priv->picture.palette); | |
346 priv->bytesperline = priv->width * priv->picture.depth / 8; | |
347 | |
2818 | 348 mp_msg(MSGT_TV, MSGL_INFO, "Picture values:\n"); |
349 mp_msg(MSGT_TV, MSGL_INFO, " Depth: %d, Palette: %d (Format: %s)\n", priv->picture.depth, | |
2802 | 350 priv->picture.palette, vo_format_name(priv->format)); |
2818 | 351 mp_msg(MSGT_TV, MSGL_INFO, " Brightness: %d, Hue: %d, Colour: %d, Contrast: %d\n", |
2802 | 352 priv->picture.brightness, priv->picture.hue, |
353 priv->picture.colour, priv->picture.contrast); | |
354 | |
355 | |
356 if (ioctl(priv->fd, VIDIOCSPICT, &priv->picture) == -1) | |
2790 | 357 { |
2818 | 358 mp_msg(MSGT_TV, MSGL_ERR, "ioctl set picture failed: %s\n", strerror(errno)); |
2802 | 359 return(0); |
2790 | 360 } |
361 | |
2802 | 362 priv->nbuf = priv->mbuf.frames; |
363 for (i=0; i < priv->nbuf; i++) | |
364 { | |
365 priv->buf[i].format = priv->picture.palette; | |
366 priv->buf[i].frame = i; | |
367 priv->buf[i].width = priv->width; | |
368 priv->buf[i].height = priv->height; | |
2818 | 369 mp_msg(MSGT_TV, MSGL_DBG2, "buffer: %d => %p\n", i, &priv->buf[i]); |
2802 | 370 } |
371 | |
372 /* start capture */ | |
373 if (ioctl(priv->fd, VIDIOCCAPTURE, &one) == -1) | |
374 { | |
2818 | 375 mp_msg(MSGT_TV, MSGL_ERR, "ioctl capture failed: %s\n", strerror(errno)); |
2802 | 376 return(0); |
377 } | |
2790 | 378 } |
379 | |
380 static int control(priv_t *priv, int cmd, void *arg) | |
381 { | |
2818 | 382 mp_msg(MSGT_TV, MSGL_DBG2, "debug: control(priv=%p, cmd=%d, arg=%p)\n", |
2802 | 383 priv, cmd, arg); |
2790 | 384 switch(cmd) |
385 { | |
2802 | 386 /* ========== GENERIC controls =========== */ |
387 case TVI_CONTROL_IS_VIDEO: | |
388 { | |
389 if (priv->capability.type & VID_TYPE_CAPTURE) | |
390 return(TVI_CONTROL_TRUE); | |
391 return(TVI_CONTROL_FALSE); | |
392 } | |
393 case TVI_CONTROL_IS_AUDIO: | |
394 return(TVI_CONTROL_FALSE); /* IMPLEMENT CHECK! */ | |
395 case TVI_CONTROL_IS_TUNER: | |
396 { | |
397 if (priv->capability.type & VID_TYPE_TUNER) | |
398 return(TVI_CONTROL_TRUE); | |
399 return(TVI_CONTROL_FALSE); | |
400 } | |
401 | |
402 /* ========== VIDEO controls =========== */ | |
2790 | 403 case TVI_CONTROL_VID_GET_FORMAT: |
2802 | 404 { |
405 int output_fmt = -1; | |
406 | |
407 #if 0 | |
408 switch(priv->palette) | |
409 { | |
410 case VIDEO_PALETTE_RGB555: | |
411 output_fmt = IMGFMT_RGB15; | |
412 break; | |
413 case VIDEO_PALETTE_RGB565: | |
414 output_fmt = IMGFMT_RGB16; | |
415 break; | |
416 case VIDEO_PALETTE_RGB24: | |
417 output_fmt = IMGFMT_RGB24; | |
418 break; | |
419 case VIDEO_PALETTE_RGB32: | |
420 output_fmt = IMGFMT_RGB32; | |
421 break; | |
422 case VIDEO_PALETTE_UYVY: | |
423 output_fmt = IMGFMT_UYVY; | |
424 break; | |
425 case VIDEO_PALETTE_YUV420P: | |
426 output_fmt = IMGFMT_YV12; | |
427 break; | |
428 default: | |
2818 | 429 mp_msg(MSGT_TV, MSGL_ERR, "no suitable output format found (%s)\n", |
2802 | 430 PALETTE(priv->palette)); |
431 return(TVI_CONTROL_FALSE); | |
432 } | |
433 #endif | |
434 output_fmt = priv->format; | |
435 (int)*(void **)arg = output_fmt; | |
2818 | 436 mp_msg(MSGT_TV, MSGL_INFO, "Output format: %s\n", vo_format_name(output_fmt)); |
2802 | 437 return(TVI_CONTROL_TRUE); |
438 } | |
439 case TVI_CONTROL_VID_SET_FORMAT: | |
440 priv->format = (int)*(void **)arg; | |
2790 | 441 return(TVI_CONTROL_TRUE); |
442 case TVI_CONTROL_VID_GET_PLANES: | |
443 (int)*(void **)arg = 1; | |
444 return(TVI_CONTROL_TRUE); | |
445 case TVI_CONTROL_VID_GET_BITS: | |
2810 | 446 (int)*(void **)arg = palette2depth(format2palette(priv->format)); |
2790 | 447 return(TVI_CONTROL_TRUE); |
448 case TVI_CONTROL_VID_GET_WIDTH: | |
449 (int)*(void **)arg = priv->width; | |
450 return(TVI_CONTROL_TRUE); | |
451 case TVI_CONTROL_VID_CHK_WIDTH: | |
452 { | |
453 int req_width = (int)*(void **)arg; | |
454 | |
2818 | 455 mp_msg(MSGT_TV, MSGL_INFO, "Requested width: %d\n", req_width); |
2810 | 456 if ((req_width >= priv->capability.minwidth) && |
457 (req_width <= priv->capability.maxwidth)) | |
2790 | 458 return(TVI_CONTROL_TRUE); |
459 return(TVI_CONTROL_FALSE); | |
460 } | |
461 case TVI_CONTROL_VID_SET_WIDTH: | |
462 priv->width = (int)*(void **)arg; | |
463 return(TVI_CONTROL_TRUE); | |
464 case TVI_CONTROL_VID_GET_HEIGHT: | |
465 (int)*(void **)arg = priv->height; | |
466 return(TVI_CONTROL_TRUE); | |
467 case TVI_CONTROL_VID_CHK_HEIGHT: | |
468 { | |
469 int req_height = (int)*(void **)arg; | |
470 | |
2818 | 471 mp_msg(MSGT_TV, MSGL_INFO, "Requested height: %d\n", req_height); |
2810 | 472 if ((req_height >= priv->capability.minheight) && |
473 (req_height <= priv->capability.maxheight)) | |
2790 | 474 return(TVI_CONTROL_TRUE); |
475 return(TVI_CONTROL_FALSE); | |
476 } | |
477 case TVI_CONTROL_VID_SET_HEIGHT: | |
478 priv->height = (int)*(void **)arg; | |
479 return(TVI_CONTROL_TRUE); | |
480 | |
2802 | 481 /* ========== TUNER controls =========== */ |
482 case TVI_CONTROL_TUN_GET_FREQ: | |
483 { | |
484 unsigned long freq; | |
485 | |
486 if (ioctl(priv->fd, VIDIOCGFREQ, &freq) == -1) | |
487 { | |
2818 | 488 mp_msg(MSGT_TV, MSGL_ERR, "ioctl get freq failed: %s\n", strerror(errno)); |
2802 | 489 return(TVI_CONTROL_FALSE); |
490 } | |
491 | |
492 /* tuner uses khz not mhz ! */ | |
493 if (priv->tuner.flags & VIDEO_TUNER_LOW) | |
494 freq /= 1000; | |
495 (unsigned long)*(void **)arg = freq; | |
496 return(TVI_CONTROL_TRUE); | |
497 } | |
2790 | 498 case TVI_CONTROL_TUN_SET_FREQ: |
499 { | |
2802 | 500 /* argument is in MHz ! */ |
501 unsigned long freq = (unsigned long)*(void **)arg; | |
502 | |
2818 | 503 mp_msg(MSGT_TV, MSGL_V, "requested frequency: %lu MHz\n", (float)freq/16); |
2802 | 504 |
505 /* tuner uses khz not mhz ! */ | |
506 if (priv->tuner.flags & VIDEO_TUNER_LOW) | |
507 freq *= 1000; | |
2818 | 508 mp_msg(MSGT_TV, MSGL_V, " requesting from driver: freq=%.3f\n", (float)freq/16); |
2802 | 509 if (ioctl(priv->fd, VIDIOCSFREQ, &freq) == -1) |
510 { | |
2818 | 511 mp_msg(MSGT_TV, MSGL_ERR, "ioctl set freq failed: %s\n", strerror(errno)); |
2802 | 512 return(TVI_CONTROL_FALSE); |
513 } | |
514 return(TVI_CONTROL_TRUE); | |
515 } | |
516 case TVI_CONTROL_TUN_GET_TUNER: | |
517 { | |
518 if (ioctl(priv->fd, VIDIOCGTUNER, &priv->tuner) == -1) | |
519 { | |
2818 | 520 mp_msg(MSGT_TV, MSGL_ERR, "ioctl get tuner failed: %s\n", strerror(errno)); |
2802 | 521 return(TVI_CONTROL_FALSE); |
522 } | |
523 | |
2818 | 524 mp_msg(MSGT_TV, MSGL_INFO, "Tuner (%s) range: %lu -> %lu\n", priv->tuner.name, |
2802 | 525 priv->tuner.rangelow, priv->tuner.rangehigh); |
526 return(TVI_CONTROL_TRUE); | |
527 } | |
528 case TVI_CONTROL_TUN_SET_TUNER: | |
529 { | |
530 if (ioctl(priv->fd, VIDIOCSTUNER, &priv->tuner) == -1) | |
531 { | |
2818 | 532 mp_msg(MSGT_TV, MSGL_ERR, "ioctl get tuner failed: %s\n", strerror(errno)); |
2802 | 533 return(TVI_CONTROL_FALSE); |
534 } | |
535 return(TVI_CONTROL_TRUE); | |
536 } | |
537 case TVI_CONTROL_TUN_SET_NORM: | |
538 { | |
539 int req_mode = (int)*(void **)arg; | |
540 | |
541 if ((!(priv->tuner.flags & VIDEO_TUNER_NORM)) || | |
542 ((req_mode == VIDEO_MODE_PAL) && !(priv->tuner.flags & VIDEO_TUNER_PAL)) || | |
543 ((req_mode == VIDEO_MODE_NTSC) && !(priv->tuner.flags & VIDEO_TUNER_NTSC)) || | |
544 ((req_mode == VIDEO_MODE_SECAM) && !(priv->tuner.flags & VIDEO_TUNER_SECAM))) | |
545 { | |
2818 | 546 mp_msg(MSGT_TV, MSGL_ERR, "Tuner isn't capable to set norm!\n"); |
2802 | 547 return(TVI_CONTROL_FALSE); |
548 } | |
549 | |
550 priv->tuner.mode = req_mode; | |
2790 | 551 |
2802 | 552 if (control(priv->fd, TVI_CONTROL_TUN_SET_TUNER, &priv->tuner) != TVI_CONTROL_TRUE) |
553 return(TVI_CONTROL_FALSE); | |
554 return(TVI_CONTROL_TRUE); | |
555 } | |
556 case TVI_CONTROL_TUN_GET_NORM: | |
557 { | |
558 (int)*(void **)arg = priv->tuner.mode; | |
559 | |
560 return(TVI_CONTROL_TRUE); | |
561 } | |
562 | |
563 /* ========== AUDIO controls =========== */ | |
564 case TVI_CONTROL_AUD_GET_FORMAT: | |
565 { | |
566 (int)*(void **)arg = AFMT_S16_LE; | |
567 return(TVI_CONTROL_TRUE); | |
568 } | |
569 case TVI_CONTROL_AUD_GET_CHANNELS: | |
570 { | |
571 (int)*(void **)arg = 2; | |
572 return(TVI_CONTROL_TRUE); | |
573 } | |
574 case TVI_CONTROL_AUD_GET_SAMPLERATE: | |
575 { | |
576 (int)*(void **)arg = 44100; | |
577 return(TVI_CONTROL_TRUE); | |
578 } | |
579 case TVI_CONTROL_AUD_GET_SAMPLESIZE: | |
580 { | |
581 (int)*(void **)arg = 76000; | |
582 return(TVI_CONTROL_TRUE); | |
583 } | |
584 | |
585 /* ========== SPECIFIC controls =========== */ | |
586 case TVI_CONTROL_SPC_GET_INPUT: | |
587 { | |
588 int req_chan = (int)*(void **)arg; | |
589 int i; | |
590 | |
591 for (i = 0; i < priv->capability.channels; i++) | |
592 { | |
593 if (priv->channels[i].channel == req_chan) | |
594 break; | |
595 } | |
596 | |
597 if (ioctl(priv->fd, VIDIOCGCHAN, &priv->channels[i]) == -1) | |
598 { | |
2818 | 599 mp_msg(MSGT_TV, MSGL_ERR, "ioctl get channel failed: %s\n", strerror(errno)); |
2802 | 600 return(TVI_CONTROL_FALSE); |
601 } | |
602 return(TVI_CONTROL_TRUE); | |
603 } | |
604 | |
605 case TVI_CONTROL_SPC_SET_INPUT: | |
606 { | |
607 struct video_channel chan; | |
608 int req_chan = (int)*(void **)arg; | |
609 int i; | |
610 | |
611 if (req_chan >= priv->capability.channels) | |
612 { | |
2818 | 613 mp_msg(MSGT_TV, MSGL_ERR, "Invalid input requested: %d, valid: 0-%d\n", |
2802 | 614 req_chan, priv->capability.channels); |
615 return(TVI_CONTROL_FALSE); | |
616 } | |
617 | |
618 for (i = 0; i < priv->capability.channels; i++) | |
619 { | |
620 if (priv->channels[i].channel == req_chan) | |
621 chan = priv->channels[i]; | |
622 } | |
623 | |
624 if (ioctl(priv->fd, VIDIOCSCHAN, &chan) == -1) | |
625 { | |
2818 | 626 mp_msg(MSGT_TV, MSGL_ERR, "ioctl set chan failed: %s\n", strerror(errno)); |
2802 | 627 return(TVI_CONTROL_FALSE); |
628 } | |
2818 | 629 mp_msg(MSGT_TV, MSGL_INFO, "Using input '%s'\n", chan.name); |
2802 | 630 |
631 /* update tuner state */ | |
632 if (priv->capability.type & VID_TYPE_TUNER) | |
633 control(priv, TVI_CONTROL_TUN_GET_TUNER, 0); | |
634 | |
635 /* update local channel list */ | |
636 control(priv, TVI_CONTROL_SPC_GET_INPUT, &req_chan); | |
637 return(TVI_CONTROL_TRUE); | |
2790 | 638 } |
639 } | |
640 | |
641 return(TVI_CONTROL_UNKNOWN); | |
642 } | |
643 | |
644 static int grab_video_frame(priv_t *priv, char *buffer, int len) | |
645 { | |
2802 | 646 int frame = priv->queue % priv->nbuf; |
2814 | 647 int nextframe = (priv->queue+1) % priv->nbuf; |
2802 | 648 |
2818 | 649 mp_msg(MSGT_TV, MSGL_DBG2, "grab_video_frame(priv=%p, buffer=%p, len=%d\n", |
2802 | 650 priv, buffer, len); |
651 | |
2818 | 652 mp_msg(MSGT_TV, MSGL_DBG3, "buf: %p + frame: %d => %p\n", |
2814 | 653 priv->buf, nextframe, &priv->buf[nextframe]); |
654 if (ioctl(priv->fd, VIDIOCMCAPTURE, &priv->buf[nextframe]) == -1) | |
2790 | 655 { |
2818 | 656 mp_msg(MSGT_TV, MSGL_ERR, "ioctl mcapture failed: %s\n", strerror(errno)); |
2802 | 657 return(0); |
2790 | 658 } |
659 | |
2814 | 660 if (ioctl(priv->fd, VIDIOCSYNC, &priv->buf[frame].frame) == -1) |
2818 | 661 mp_msg(MSGT_TV, MSGL_ERR, "ioctl sync failed: %s\n", strerror(errno)); |
2802 | 662 priv->queue++; |
663 | |
2818 | 664 mp_msg(MSGT_TV, MSGL_DBG3, "mmap: %p + offset: %d => %p\n", |
2802 | 665 priv->mmap, priv->mbuf.offsets[frame], |
666 priv->mmap+priv->mbuf.offsets[frame]); | |
667 memcpy(buffer, priv->mmap+priv->mbuf.offsets[frame], len); | |
668 | |
669 return(len); | |
2790 | 670 } |
671 | |
672 static int get_video_framesize(priv_t *priv) | |
673 { | |
2802 | 674 return priv->bytesperline * priv->height; |
2790 | 675 } |
676 | |
677 static int grab_audio_frame(priv_t *priv, char *buffer, int len) | |
678 { | |
679 } | |
680 | |
681 static int get_audio_framesize(priv_t *priv) | |
682 { | |
683 return 65536; | |
684 } | |
685 | |
686 #endif /* USE_TV */ |