Hi,
The current method used in mplayer to detect an PVR350 at the
ivtv-vidix-driver fails, if the PVR350 is not the first ivtv-card and
you haven't set FRAMEBUFFER in your environment.
I developed a patch against the current trunk of mplayer, which
iterates through the /sys/class/video4linux/video an
/sys/class/graphics/fb directories or, if they are not present, the
/dev/video and /dev/fb files.
VIDIOC_QUERYCAP tells me the right driver and capabilites of the found
devices and like the example in the v4l2-spec I search for the related
framebuffer.
The only hack is a missing possibility of distinguish the multiple
devices of a PVR350 (video0, video16, video32, video48 etc) to get the
YUV-decoder. v4l2 returns the same capabilities for every device. The
code has to know it's at video48+x.
Since this is my first v4l2-related coding, some ivtv/v4l2-prof can
have a look at it, that I'm doing things right. After that I would post
it at mplayer-dev-eng.
Lars.
Index: vidix/ivtv_vid.c
===================================================================
--- vidix/ivtv_vid.c (Revision 26994)
+++ vidix/ivtv_vid.c (Arbeitskopie)
@@ -22,6 +22,7 @@
*/
#include <errno.h>
+#include <glob.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -30,6 +31,7 @@
#include <inttypes.h>
#include <fcntl.h>
#include <sys/ioctl.h>
+#include <sys/stat.h>
#include <linux/types.h>
#include <linux/version.h>
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
@@ -224,100 +226,173 @@
int ivtv_probe(int verbose,int force __attribute__ ((unused)))
{
- unsigned char fb_number = 0;
- char *device_name = NULL;
- char *alpha = NULL;
- struct fb_var_screeninfo vinfo;
- char fb_dev_name[] = "/dev/fb0\0";
- pciinfo_t lst[MAX_PCI_DEVICES];
- int err = 0;
- unsigned int i, num_pci = 0;
+ int i;
+ struct stat fileStat;
+ char sysfsVideoClass[] = "/sys/class/video4linux\0";
+ char sysfsGraphicsClass[] = "/sys/class/graphics\0";
+ char *yuv_searchPattern[] = { "/sys/class/video4linux/video*\0",
"/dev/video*\0"};
+ char *fb_searchPattern[] = { "/sys/class/graphics/fb*\0",
"/dev/fb*\0"};
+ int yuv_patNr = 0;
+ int fb_patNr = 0;
+ glob_t searchResult;
+ char deviceName[] = "/dev/videoXXXXX\0";
+ int devLen = 0;
+ struct v4l2_capability vcap;
+ struct v4l2_fmtdesc vfdesc;
+ int found_yuv_format = 0;
+ char *tmpStr = 0;
+ int yuvDevNumber = -1;
+ struct v4l2_framebuffer fbuf;
+ struct fb_fix_screeninfo fbsi;
if(verbose)
- printf(IVTV_MSG"probe\n");
-
+ printf(IVTV_MSG"probe\n");
+
ivtv_verbose = verbose;
+
+ /* test if sysfs is present, otherwise fallback to /dev */
+ if(access(sysfsVideoClass, F_OK) < 0)
+ yuv_patNr = 1;
+ if(access(sysfsGraphicsClass, F_OK) < 0)
+ fb_patNr = 1;
- err = pci_scan(lst, &num_pci);
- if(err) {
- printf(IVTV_MSG"Error occured during pci scan: %s\n",
strerror(err));
- return err;
- }
+ /* search for the installed video devices */
+ if(glob(yuv_searchPattern[yuv_patNr], GLOB_MARK, 0, &searchResult) ==
0) {
+ for(i = 0; (yuvDevNumber < 0) && (i < searchResult.gl_pathc);
i++) {
+ if(stat(searchResult.gl_pathv[i], &fileStat) == 0) {
+ devLen = 0;
+ if((yuv_patNr == 0) &&
S_ISDIR(fileStat.st_mode)) {
+ /* get the related device-node */
+ snprintf(deviceName,
sizeof(deviceName), "/dev/%s", searchResult.gl_pathv[i] +
strlen(sysfsVideoClass) + 1);
+ devLen = strlen(deviceName);
+ if(deviceName[devLen - 1] == '/') {
+ devLen--;
+ deviceName[devLen]= 0;
+ }
+ } else if((yuv_patNr == 1) &&
!S_ISDIR(fileStat.st_mode)) {
+ snprintf(deviceName,
sizeof(deviceName), "%s", searchResult.gl_pathv[i]);
+ devLen = strlen(deviceName);
+ }
+
+ if(devLen > 0) {
+ yuvdev = open(deviceName, O_RDONLY);
+ if(-1 == yuvdev) {
+ printf(IVTV_MSG"Error occured
during opening %s\n", deviceName);
+ } else {
+ if(ioctl(yuvdev,
VIDIOC_QUERYCAP, &vcap) < 0) {
+ printf(IVTV_MSG"unable
to query capabilites of %s\n", deviceName);
+ } else if(strncmp(vcap.driver,
"ivtv", 4) == 0) {
+ if(vcap.capabilities &
V4L2_CAP_VIDEO_OUTPUT) {
+ /* it is a
device handled by ivtv and it has an output */
+ vfdesc.index =
0;
+ vfdesc.type =
V4L2_BUF_TYPE_VIDEO_OUTPUT;
+
found_yuv_format = 0;
+
while(ioctl(yuvdev, VIDIOC_ENUM_FMT, &vfdesc) == 0) {
+
if(vfdesc.pixelformat == V4L2_PIX_FMT_HM12) {
+
found_yuv_format= 1;
+
break;
+ }
+
vfdesc.index++;
+ }
+
if(found_yuv_format) {
+ /* it
supports the needed pixel format */
- if(ivtv_verbose)
- printf(IVTV_MSG"Found %d pci devices\n", num_pci);
-
- for(i = 0; i < num_pci; i++) {
- if(2 == ivtv_verbose)
- printf(IVTV_MSG"Found chip [%04X:%04X] '%s' '%s'\n"
- ,lst[i].vendor
- ,lst[i].device
- ,pci_vendor_name(lst[i].vendor)
- ,pci_device_name(lst[i].vendor,lst[i].device));
- if(VENDOR_INTERNEXT == lst[i].vendor) {
- switch(lst[i].device)
- {
- case DEVICE_INTERNEXT_ITVC15_MPEG_2_ENCODER:
- if(ivtv_verbose)
- printf(IVTV_MSG"Found PVR 350\n");
- goto card_found;
+ /* hack
is here
+ there
is a problem at the v4l2-api
+ a
PVR350 has multiple devices
+
/dev/video0
+
/dev/video16
+
/dev/video32
+
/dev/video48
+
VIDIOC_QUERYCAP returns the same for every device
+ so the
code has to know that the YUV-decoder is
+ at
/dev/video48 or higher
+
+ maybe
this is solved in the future...
+ */
+ tmpStr
= deviceName + devLen;
+
while((tmpStr >= deviceName) && isdigit((tmpStr-1)[0]))
+
tmpStr--;
+
if(tmpStr > deviceName) {
+
yuvDevNumber = atoi(tmpStr);
+
/* which one of the devices of the PVR350 have I found? */
+
if(yuvDevNumber >= 48) {
+
/* this is the right device, do nothing */
+
} else if(yuvDevNumber >= 32) {
+
yuvDevNumber = 48 + yuvDevNumber - 32;
+
} else if(yuvDevNumber >= 16) {
+
yuvDevNumber = 48 + yuvDevNumber - 16;
+
} else if(yuvDevNumber >= 0) {
+
yuvDevNumber = 48 + yuvDevNumber - 0;
+
} else
+
yuvDevNumber = -1;
+ }
+ }
+ }
+ }
+ close(yuvdev);
+ yuvdev = -1;
+ }
+ }
}
}
}
-
- if(ivtv_verbose)
- printf(IVTV_MSG"Can't find chip\n");
- return ENXIO;
-
-card_found:
-
- device_name = getenv("FRAMEBUFFER");
- if(NULL == device_name) {
- device_name = fb_dev_name;
+ globfree(&searchResult);
+ if(yuvDevNumber < 0) {
+ printf(IVTV_MSG"no ivtv-driven yuv-decoder found\n");
+ return ENXIO;
}
- fb_number = atoi(device_name+strlen("/dev/fb"));
-
- fbdev = open(device_name, O_RDWR);
- if(-1 != fbdev) {
- if(ioctl(fbdev, FBIOGET_VSCREENINFO, &vinfo) < 0) {
- printf(IVTV_MSG"Unable to read screen info\n");
- close(fbdev);
- return ENXIO;
- } else {
- fb_width = vinfo.xres;
- fb_height = vinfo.yres;
- if(2 == ivtv_verbose) {
- printf(IVTV_MSG"framebuffer width :
%3.0f\n",fb_width);
- printf(IVTV_MSG"framebuffer height:
%3.0f\n",fb_height);
+ snprintf(deviceName, sizeof(deviceName), "/dev/video%d", yuvDevNumber);
+ yuvdev = open(deviceName, O_RDWR);
+ if(-1 == yuvdev) {
+ printf(IVTV_MSG"Error opening yuv-decoder %s\n", deviceName);
+ } else {
+ if(verbose)
+ printf(IVTV_MSG"Found yuv-decoder %s\n", deviceName);
+ if(ioctl(yuvdev, VIDIOC_G_FBUF, &fbuf) == 0) {
+ /* searching for the related framebuffer-device */
+ if(glob(fb_searchPattern[fb_patNr], GLOB_MARK, 0,
&searchResult) == 0) {
+ for(i = 0; i < searchResult.gl_pathc; i++) {
+ if(stat(searchResult.gl_pathv[ i],
&fileStat) == 0) {
+ devLen = 0;
+ if((fb_patNr == 0) &&
S_ISDIR(fileStat.st_mode)) {
+ snprintf(deviceName,
sizeof(deviceName), "/dev/%s", searchResult.gl_pathv[i] +
strlen(sysfsGraphicsClass) + 1);
+ devLen = strlen(
deviceName);
+ if(deviceName[devLen -
1] == '/') {
+ devLen--;
+
deviceName[devLen] = 0;
+ }
+ } else if((fb_patNr == 1) &&
!S_ISDIR(fileStat.st_mode)) {
+ snprintf(deviceName,
sizeof(deviceName), "%s", searchResult.gl_pathv[i]);
+ devLen =
strlen(deviceName);
+ }
+
+ if(devLen > 0) {
+ fbdev =
open(deviceName, O_RDWR);
+ if(-1 == fbdev) {
+
printf(IVTV_MSG"Error occured during opening %s\n", deviceName);
+ } else {
+ if(0 ==
ioctl(fbdev, FBIOGET_FSCREENINFO, &fbsi)) {
+
if(fbsi.smem_start == (unsigned long) fbuf.base)
+
break; /* found it */
+ }
+ close(fbdev);
+ fbdev = -1;
+ }
+ }
+ }
+ }
+ globfree(&searchResult);
}
}
- if(NULL != (alpha = getenv("VIDIXIVTVALPHA"))) {
- if(0 == strcmp(alpha, "disable")) {
- alpha_disable = 1;
- }
- }
- } else {
- printf(IVTV_MSG"Failed to open /dev/fb%u\n", fb_number);
- return ENXIO;
+ if(-1 == fbdev) {
+ printf(IVTV_MSG"no related framebuffer found\n");
+ close(yuvdev);
+ yuvdev = -1;
+ } else
+ goto yuv_found;
}
-
- /* Try to find YUV device */
- unsigned char yuv_device_number = 48, yuv_device = 48 + fb_number;
- char yuv_device_name[] = "/dev/videoXXX\0";
-
- do {
- sprintf(yuv_device_name, "/dev/video%u", yuv_device);
- yuvdev = open(yuv_device_name, O_RDWR);
- if(-1 != yuvdev) {
- if(ivtv_verbose)
- printf(IVTV_MSG"YUV device found
/dev/video%u\n", yuv_device);
- goto yuv_found;
- } else {
- if(ivtv_verbose)
- printf(IVTV_MSG"YUV device not found:
/dev/video%u\n", yuv_device);
- }
- } while(yuv_device-- > yuv_device_number);
return ENXIO;
yuv_found:
_______________________________________________
ivtv-devel mailing list
[email protected]
http://ivtvdriver.org/mailman/listinfo/ivtv-devel