ioctl calls on fd passed from Java UsbManager

311 views
Skip to first unread message

Benedikt Tutzer

unread,
Apr 12, 2016, 8:09:47 PM4/12/16
to android-ndk
Hi.
I am trying to communicate with a Webcam connected via USB. Since I do not have permissions on /dev/video4 (the device node for my webcam) I thought it would be best to ask for permission via the UsbManager class and then pass the file descriptor to C. This looks good, the fd is a read-write file descriptor and is open (both checked with fcntl), but whenever I try to perform any ioctl calls, I get a ENOTTY error.
This is how I pass the descriptor:
private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {

   
public void onReceive(Context context, Intent intent) {
       
String action = intent.getAction();
       
if (ACTION_USB_PERMISSION.equals(action)) {
           
synchronized (this) {
               
UsbDevice device = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);

               
if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
                   
if(device != null){
                       
Log.v(TAG, "connected to " + device);
                       
UsbDeviceConnection con = manager.openDevice(device);
                       
int fd = con.getFileDescriptor();
                       
Log.e(TAG, "fd " +fd);
                       
int ret = new V4L2Camera(fd, null, 640, 480, 30).initCamera();
                   
}
               
}
               
else {
                   
Log.d(TAG, "permission denied for device " + device);
               
}
           
}
       
}
   
}
};
And here is the calls to ioctl_loop
jint ...nInitCamera
 
(JNIEnv *env, jobject obj){
   
struct v4l2_capability capability;
   
struct v4l2_cropcap cropcap;
   
struct v4l2_crop crop;
   
struct v4l2_format format;
   
unsigned int min;

    jclass
ClassV4L2Camera = env->GetObjectClass(obj);
    jfieldID fdID
= env->GetFieldID(ClassV4L2Camera, "fd", "I");
    jfieldID widthID
= env->GetFieldID(ClassV4L2Camera, "width", "I");
    jfieldID heightID
= env->GetFieldID(ClassV4L2Camera, "height", "I");
   
int fd = env->GetIntField(obj, fdID);

    int width = env->GetIntField(obj, widthID);
   
int height = env->GetIntField(obj, heightID);

   
if (ioctl_loop(fd, VIDIOC_QUERYCAP, &capability) == -1) {
     
if (errno == EINVAL) {
         LOGE
("Device does not have any V4L capabilities");
         
return ERROR_NO_V4L_DEVICE;
     
} else {
         if (errno == ENOTTY)
            LOGE("ENOTTY");
         
return ERROR_CAPABILITIES_QUERRY;
     
}
   
}
....
This is the actual call to ioctl, I just retry until I do not get EINTR. In fact, I get ENOTTY.
int ioctl_loop(int fd, int request, void *arg)
{
int r;

do r = ioctl (fd, request, arg);
while (-1 == r && EINTR == errno);

return r;
}
Does anybody have an Idea why the ioctl calls do not work? I am sure the VIDIOC_QUERYCAP must work with any UVC camera, and all the cameras I have tried are UVC compliant.
I am stuck on this for quite some time, any input is very valuable to me. Thanks in advance.

Benedikt Tutzer

unread,
Apr 13, 2016, 2:34:18 PM4/13/16
to android-ndk
I just found out whats wrong. The UsbDeviceConnection filedescriptor points to the generic /dev/bus/usb/001/004, but to send the V4L ioctl's I need the pointer to /dev/video4, the device file created by the V4L kernel module. Can I somehow tell the device I want to use the V4L file?
I cannot open /dev/video4 directly because I do not have the necessary permissions (although the file has the same permissions).
My only idea would be to somehow build a userspace V4L library, I should then be able to open /dev/bus/usb/001/004, but I would prefer to use the build in V4L module.

יהודה שר שלום

unread,
Mar 15, 2017, 4:55:49 PM3/15/17
to android-ndk

you can use libuvc

בתאריך יום רביעי, 13 באפריל 2016 בשעה 21:34:18 UTC+3, מאת Benedikt Tutzer:
Reply all
Reply to author
Forward
0 new messages