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