Mercurial > mplayer.hg
comparison vidix/ivtv_vid.c @ 23275:17fcd644f32e
new VIDIX driver for IVTV cards, original patch by Lutz Koschorreck
author | ben |
---|---|
date | Thu, 10 May 2007 18:47:27 +0000 |
parents | |
children | 334d55a31174 |
comparison
equal
deleted
inserted
replaced
23274:f3e72ce8a9fd | 23275:17fcd644f32e |
---|---|
1 /** | |
2 VIDIX driver for Hauppauge PVR 350. | |
3 | |
4 Copyright 2007 Lutz Koschorreck. | |
5 | |
6 Based on genfb_vid.c and ivtv_xv.c | |
7 | |
8 This program is free software; you can redistribute it and/or modify | |
9 it under the terms of the GNU General Public License as published by | |
10 the Free Software Foundation; either version 2 of the License, or | |
11 (at your option) any later version. | |
12 | |
13 This program is distributed in the hope that it will be useful, | |
14 but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 GNU General Public License for more details. | |
17 | |
18 You should have received a copy of the GNU General Public License | |
19 along with this program; if not, write to the Free Software | |
20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
21 | |
22 09.05.2007 Lutz Koschorreck | |
23 First version: Tested with ivtv-0.10.1, xine-ui-0.99.5, xine-lib-1.1.6 | |
24 | |
25 **/ | |
26 | |
27 #include <errno.h> | |
28 #include <stdio.h> | |
29 #include <stdlib.h> | |
30 #include <string.h> | |
31 #include <unistd.h> | |
32 #include <math.h> | |
33 #include <inttypes.h> | |
34 #include <fcntl.h> | |
35 #include <sys/ioctl.h> | |
36 #include <linux/types.h> | |
37 #include <linux/ivtv.h> | |
38 | |
39 #include "vidix.h" | |
40 #include "vidixlib.h" | |
41 #include "fourcc.h" | |
42 #include "dha.h" | |
43 #include "pci_ids.h" | |
44 #include "pci_names.h" | |
45 | |
46 #define VIDIX_STATIC ivtv_ | |
47 | |
48 #define IVTV_MSG "[ivtv-vid] " | |
49 #define MAXLINE 128 | |
50 #define IVTVMAXWIDTH 720 | |
51 #define IVTVMAXHEIGHT 576 | |
52 | |
53 static int yuvdev = 0; | |
54 static void *memBase = 0; | |
55 static int frameSize = 0; | |
56 static int probed = 0; | |
57 static int ivtv_verbose; | |
58 static vidix_rect_t destVideo; | |
59 static vidix_rect_t srcVideo; | |
60 static unsigned char *outbuf = NULL; | |
61 | |
62 /* VIDIX exports */ | |
63 | |
64 static vidix_capability_t ivtv_cap = | |
65 { | |
66 "Hauppauge PVR 350 YUV Video", | |
67 "Lutz Koschorreck", | |
68 TYPE_OUTPUT, | |
69 { 0, 0, 0, 0 }, | |
70 IVTVMAXHEIGHT, | |
71 IVTVMAXWIDTH, | |
72 4, | |
73 4, | |
74 -1, | |
75 FLAG_UPSCALER|FLAG_DOWNSCALER, | |
76 -1, | |
77 -1, | |
78 { 0, 0, 0, 0 } | |
79 }; | |
80 | |
81 static void de_macro_y (unsigned char *src, unsigned char *dst, | |
82 unsigned int w, unsigned int h, | |
83 int src_x, int src_y, | |
84 int height __attribute__ ((unused)), int width) | |
85 { | |
86 unsigned int x, y, i; | |
87 unsigned char *dst_2; | |
88 unsigned int h_tail, w_tail; | |
89 unsigned int h_size, w_size; | |
90 | |
91 // Always round the origin, but compensate by increasing the size | |
92 if (src_x & 15) | |
93 { | |
94 w += src_x & 15; | |
95 src_x &= ~15; | |
96 } | |
97 | |
98 if (src_y & 15) | |
99 { | |
100 h += src_y & 15; | |
101 src_y &= ~15; | |
102 } | |
103 | |
104 // The right / bottom edge might not be a multiple of 16 | |
105 h_tail = h & 15; | |
106 w_tail = w & 15; | |
107 | |
108 // One block is 16 pixels high | |
109 h_size = 16; | |
110 | |
111 // descramble Y plane | |
112 for (y = 0; y < h; y += 16) | |
113 { | |
114 // Clip if we've reached the bottom & the size isn't a multiple of 16 | |
115 if (y + 16 > h) h_size = h_tail; | |
116 | |
117 for (x = 0; x < w; x += 16) | |
118 { | |
119 if (x + 16 > w) | |
120 w_size = w_tail; | |
121 else | |
122 w_size = 16; | |
123 | |
124 dst_2 = dst + (720 * y) + (720 * src_y) + (256 * (src_x>>4)) + (x * 16); | |
125 | |
126 for (i = 0; i < h_size; i++) | |
127 { | |
128 memcpy (dst_2, src + src_x + x + (y + i) * width + (src_y * width), | |
129 w_size); | |
130 dst_2 += 16; | |
131 } | |
132 } | |
133 } | |
134 } | |
135 | |
136 static void de_macro_uv (unsigned char *srcu, unsigned char *srcv, | |
137 unsigned char *dst, unsigned int w, unsigned int h, | |
138 int src_x, int src_y, int height, int width) | |
139 { | |
140 unsigned int x, y, i, f; | |
141 unsigned char *dst_2; | |
142 unsigned int h_tail, w_tail; | |
143 unsigned int h_size; | |
144 | |
145 /* The uv plane is half the size of the y plane, | |
146 so 'correct' all dimensions. */ | |
147 w /= 2; | |
148 h /= 2; | |
149 src_x /= 2; | |
150 src_y /= 2; | |
151 height /= 2; | |
152 width /= 2; | |
153 | |
154 // Always round the origin, but compensate by increasing the size | |
155 if (src_x & 7) | |
156 { | |
157 w += src_x & 7; | |
158 src_x &= ~7; | |
159 } | |
160 | |
161 if (src_y & 15) | |
162 { | |
163 h += src_y & 15; | |
164 src_y &= ~15; | |
165 } | |
166 | |
167 // The right / bottom edge may not be a multiple of 16 | |
168 h_tail = h & 15; | |
169 w_tail = w & 7; | |
170 | |
171 h_size = 16; | |
172 | |
173 // descramble U/V plane | |
174 for (y = 0; y < h; y += 16) | |
175 { | |
176 if (y + 16 > h) | |
177 h_size = h_tail; | |
178 | |
179 for (x = 0; x < w; x += 8) | |
180 { | |
181 dst_2 = dst + (720 * y) + (720 * src_y) + (256 * (src_x>>3)) + (x * 32); | |
182 if (x + 8 <= w) | |
183 { | |
184 for (i = 0; i < h_size; i++) | |
185 { | |
186 int idx = src_x + x + ((y + i) * width) + (src_y * width); | |
187 dst_2[0] = srcu[idx + 0]; | |
188 dst_2[1] = srcv[idx + 0]; | |
189 dst_2[2] = srcu[idx + 1]; | |
190 dst_2[3] = srcv[idx + 1]; | |
191 dst_2[4] = srcu[idx + 2]; | |
192 dst_2[5] = srcv[idx + 2]; | |
193 dst_2[6] = srcu[idx + 3]; | |
194 dst_2[7] = srcv[idx + 3]; | |
195 dst_2[8] = srcu[idx + 4]; | |
196 dst_2[9] = srcv[idx + 4]; | |
197 dst_2[10] = srcu[idx + 5]; | |
198 dst_2[11] = srcv[idx + 5]; | |
199 dst_2[12] = srcu[idx + 6]; | |
200 dst_2[13] = srcv[idx + 6]; | |
201 dst_2[14] = srcu[idx + 7]; | |
202 dst_2[15] = srcv[idx + 7]; | |
203 dst_2 += 16; | |
204 } | |
205 } | |
206 else | |
207 { | |
208 for (i = 0; i < h_size; i ++) | |
209 { | |
210 int idx = src_x + x + ((y + i) * width) + (src_y * width); | |
211 for (f = 0; f < w_tail; f++) | |
212 { | |
213 dst_2[0] = srcu[idx + f]; | |
214 dst_2[1] = srcv[idx + f]; | |
215 dst_2 += 2; | |
216 } | |
217 | |
218 dst_2 += 16 - (w_tail << 1); | |
219 } | |
220 } | |
221 } | |
222 } | |
223 } | |
224 | |
225 static int ivtv_probe (int verbose, int force __attribute__ ((unused))) | |
226 { | |
227 pciinfo_t lst[MAX_PCI_DEVICES]; | |
228 unsigned int i, num_pci; | |
229 int err; | |
230 FILE *procFb; | |
231 unsigned char fb_number = 0; | |
232 unsigned char yuv_device_number, yuv_device; | |
233 char yuv_device_name[] = "/dev/videoXXX\0"; | |
234 | |
235 if (verbose) | |
236 printf (IVTV_MSG"probe\n"); | |
237 | |
238 ivtv_verbose = verbose; | |
239 | |
240 err = pci_scan (lst, &num_pci); | |
241 if (err) | |
242 { | |
243 printf (IVTV_MSG"Error occured during pci scan: %s\n", strerror (err)); | |
244 return err; | |
245 } | |
246 | |
247 if (ivtv_verbose) | |
248 printf (IVTV_MSG"Found %d pci devices\n", num_pci); | |
249 | |
250 for (i = 0; i < num_pci; i++) | |
251 { | |
252 if (ivtv_verbose == 2) | |
253 printf (IVTV_MSG"Found chip [%04X:%04X] '%s' '%s'\n", | |
254 lst[i].vendor, lst[i].device, pci_vendor_name (lst[i].vendor), | |
255 pci_device_name(lst[i].vendor,lst[i].device)); | |
256 | |
257 if (VENDOR_INTERNEXT == lst[i].vendor) | |
258 { | |
259 switch (lst[i].device) | |
260 { | |
261 case DEVICE_INTERNEXT_ITVC15_MPEG_2_ENCODER: | |
262 if (ivtv_verbose) | |
263 printf (IVTV_MSG"Found PVR 350\n"); | |
264 goto card_found; | |
265 } | |
266 } | |
267 } | |
268 | |
269 if (ivtv_verbose) | |
270 printf (IVTV_MSG"Can't find chip\n"); | |
271 | |
272 return (ENXIO); | |
273 | |
274 card_found: | |
275 | |
276 /* Try to find framebuffer device */ | |
277 procFb = fopen ("/proc/fb", "r"); | |
278 if (procFb) | |
279 { | |
280 char procEntry[MAXLINE] = {0}; | |
281 while (NULL != fgets(procEntry, MAXLINE, procFb)) | |
282 { | |
283 char *pos = NULL; | |
284 if (ivtv_verbose) | |
285 printf (IVTV_MSG" %s", procEntry); | |
286 | |
287 if (NULL != (pos = strstr(procEntry, " cx23415 TV out"))) | |
288 { | |
289 *pos = '\0'; | |
290 fb_number = atoi (procEntry); | |
291 if (ivtv_verbose) | |
292 printf (IVTV_MSG"Framebuffer found #%u\n", fb_number); | |
293 goto fb_found; | |
294 } | |
295 } | |
296 } | |
297 else | |
298 { | |
299 if (ivtv_verbose) | |
300 printf (IVTV_MSG"Framebuffer device not found\n"); | |
301 return (ENXIO); | |
302 } | |
303 | |
304 fb_found: | |
305 fclose (procFb); | |
306 | |
307 /* Try to find YUV device */ | |
308 yuv_device_number = 48; | |
309 yuv_device = 48 + fb_number; | |
310 | |
311 do { | |
312 sprintf (yuv_device_name, "/dev/video%u", yuv_device); | |
313 yuvdev = open (yuv_device_name, O_RDWR); | |
314 if (-1 != yuvdev) | |
315 { | |
316 if (ivtv_verbose) | |
317 printf (IVTV_MSG"YUV device found /dev/video%u\n", yuv_device); | |
318 goto yuv_found; | |
319 } | |
320 else | |
321 { | |
322 if (ivtv_verbose) | |
323 printf (IVTV_MSG"YUV device not found: /dev/video%u\n", yuv_device); | |
324 } | |
325 } while (yuv_device-- > yuv_device_number); | |
326 | |
327 return (ENXIO); | |
328 | |
329 yuv_found: | |
330 probed = 1; | |
331 return 0; | |
332 } | |
333 | |
334 static int ivtv_init (void) | |
335 { | |
336 if (ivtv_verbose) | |
337 printf (IVTV_MSG"init\n"); | |
338 | |
339 if (!probed) | |
340 { | |
341 if (ivtv_verbose) | |
342 printf (IVTV_MSG"Driver was not probed but is being initialized\n"); | |
343 | |
344 return (EINTR); | |
345 } | |
346 | |
347 outbuf = malloc ((IVTVMAXHEIGHT * IVTVMAXWIDTH) | |
348 + (IVTVMAXHEIGHT * IVTVMAXWIDTH / 2)); | |
349 | |
350 if (!outbuf) | |
351 { | |
352 if (ivtv_verbose) | |
353 printf (IVTV_MSG"Not enough memory availabe!\n"); | |
354 return (EINTR); | |
355 } | |
356 | |
357 return 0; | |
358 } | |
359 | |
360 static void ivtv_destroy (void) | |
361 { | |
362 if (ivtv_verbose) | |
363 printf (IVTV_MSG"destory\n"); | |
364 close (yuvdev); | |
365 free (outbuf); | |
366 } | |
367 | |
368 static int ivtv_get_caps (vidix_capability_t *to) | |
369 { | |
370 if (ivtv_verbose) | |
371 printf (IVTV_MSG"GetCap\n"); | |
372 memcpy (to, &ivtv_cap, sizeof (vidix_capability_t)); | |
373 | |
374 return 0; | |
375 } | |
376 | |
377 static int ivtv_query_fourcc (vidix_fourcc_t *to) | |
378 { | |
379 int supports = 0; | |
380 | |
381 if (ivtv_verbose) | |
382 printf (IVTV_MSG"query fourcc (%x)\n", to->fourcc); | |
383 | |
384 switch (to->fourcc) | |
385 { | |
386 case IMGFMT_YV12: | |
387 supports = 1; | |
388 break; | |
389 default: | |
390 supports = 0; | |
391 } | |
392 | |
393 if (!supports) | |
394 { | |
395 to->depth = to->flags = 0; | |
396 return (ENOTSUP); | |
397 } | |
398 | |
399 to->depth = VID_DEPTH_12BPP | | |
400 VID_DEPTH_15BPP | VID_DEPTH_16BPP | | |
401 VID_DEPTH_24BPP | VID_DEPTH_32BPP; | |
402 to->flags = 0; | |
403 | |
404 return 0; | |
405 } | |
406 | |
407 static int ivtv_config_playback (vidix_playback_t *info) | |
408 { | |
409 if (ivtv_verbose) | |
410 printf (IVTV_MSG"config playback\n"); | |
411 | |
412 if (2 == ivtv_verbose) | |
413 { | |
414 printf (IVTV_MSG"src : x:%d y:%d w:%d h:%d\n", | |
415 info->src.x, info->src.y, info->src.w, info->src.h); | |
416 printf (IVTV_MSG"dest: x:%d y:%d w:%d h:%d\n", | |
417 info->dest.x, info->dest.y, info->dest.w, info->dest.h); | |
418 } | |
419 | |
420 memcpy (&destVideo, &info->dest, sizeof (vidix_rect_t)); | |
421 memcpy (&srcVideo, &info->src, sizeof (vidix_rect_t)); | |
422 | |
423 info->num_frames = 2; | |
424 info->frame_size = frameSize = | |
425 info->src.w*info->src.h+(info->src.w*info->src.h)/2; | |
426 info->dest.pitch.y = 16; | |
427 info->dest.pitch.u = info->dest.pitch.v = 16; | |
428 info->offsets[0] = 0; | |
429 info->offsets[1] = info->frame_size; | |
430 info->offset.y = 0; | |
431 info->offset.u = IVTVMAXWIDTH * IVTVMAXHEIGHT; | |
432 info->offset.v = IVTVMAXWIDTH * IVTVMAXHEIGHT | |
433 + (IVTVMAXWIDTH / 2) * (IVTVMAXHEIGHT / 2); | |
434 | |
435 info->dga_addr = memBase = malloc (info->num_frames*info->frame_size); | |
436 | |
437 if (ivtv_verbose) | |
438 printf (IVTV_MSG"frame_size: %d, dga_addr: %p\n", | |
439 info->frame_size, info->dga_addr); | |
440 | |
441 return 0; | |
442 } | |
443 | |
444 static int ivtv_playback_on (void) | |
445 { | |
446 if (ivtv_verbose) | |
447 printf (IVTV_MSG"playback on\n"); | |
448 | |
449 return 0; | |
450 } | |
451 | |
452 static int ivtv_playback_off (void) | |
453 { | |
454 if (ivtv_verbose) | |
455 printf (IVTV_MSG"playback off\n"); | |
456 | |
457 return 0; | |
458 } | |
459 | |
460 static int ivtv_frame_sel (unsigned int frame) | |
461 { | |
462 struct ivtvyuv_ioctl_dma_host_to_ivtv_args args; | |
463 | |
464 de_macro_y ((memBase + (frame * frameSize)), | |
465 outbuf, srcVideo.w, srcVideo.h, | |
466 srcVideo.x, srcVideo.y, destVideo.h, destVideo.w); | |
467 | |
468 de_macro_uv ((memBase + (frame * frameSize)) | |
469 + (srcVideo.w * srcVideo.h) + srcVideo.w * srcVideo.h / 4, | |
470 (memBase + (frame * frameSize)) + (srcVideo.w * srcVideo.h), | |
471 outbuf + IVTVMAXWIDTH * IVTVMAXHEIGHT, | |
472 srcVideo.w, srcVideo.h, srcVideo.x, srcVideo.y, | |
473 destVideo.h, destVideo.w); | |
474 | |
475 args.y_source = outbuf; | |
476 args.uv_source = outbuf + (IVTVMAXWIDTH * IVTVMAXHEIGHT); | |
477 args.src_x = srcVideo.x; | |
478 args.src_y = srcVideo.y; | |
479 args.dst_x = destVideo.x; | |
480 args.dst_y = destVideo.y; | |
481 args.src_w = srcVideo.w; | |
482 args.dst_w = destVideo.w; | |
483 args.srcBuf_width = srcVideo.w; | |
484 args.src_h = srcVideo.h; | |
485 args.dst_h = destVideo.h; | |
486 args.srcBuf_height = srcVideo.h; | |
487 args.yuv_type = 0; | |
488 | |
489 if(ioctl(yuvdev, IVTV_IOC_PREP_FRAME_YUV, &args) == -1) | |
490 printf ("Ioctl IVTV_IOC_PREP_FRAME_YUV returned failed Error\n"); | |
491 | |
492 return 0; | |
493 } | |
494 | |
495 VDXDriver ivtv_drv = { | |
496 "ivtv", | |
497 NULL, | |
498 .probe = ivtv_probe, | |
499 .get_caps = ivtv_get_caps, | |
500 .query_fourcc = ivtv_query_fourcc, | |
501 .init = ivtv_init, | |
502 .destroy = ivtv_destroy, | |
503 .config_playback = ivtv_config_playback, | |
504 .playback_on = ivtv_playback_on, | |
505 .playback_off = ivtv_playback_off, | |
506 .frame_sel = ivtv_frame_sel, | |
507 }; |