Acquiring image using v4ctl api

Hi everyone,

I am trying to write some C code to acquire a single image using the v4ctl library. I am using a raspberry pi v2 camera (IMX219) with a jetson nano.

I have the following code:

#include <errno.h>
#include <fcntl.h>
#include <linux/videodev2.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <unistd.h>

uint8_t *buffer;
 
static int xioctl(int fd, int request, void *arg)
{
        int r;
 
        do r = ioctl (fd, request, arg);
        while (-1 == r && EINTR == errno);
 
        return r;
}
 
int print_caps(int fd)
{
        struct v4l2_capability caps = {0};
        if (-1 == xioctl(fd, VIDIOC_QUERYCAP, &caps))
        {
                perror("Querying Capabilities");
                return 1;
        }
 
        printf( "Driver Caps:\n"
                "  Driver: \"%s\"\n"
                "  Card: \"%s\"\n"
                "  Bus: \"%s\"\n"
                "  Version: %d.%d\n"
                "  Capabilities: %08x\n",
                caps.driver,
                caps.card,
                caps.bus_info,
                (caps.version>>16)&&0xff,
                (caps.version>>24)&&0xff,
                caps.capabilities);
 
 
        // struct v4l2_cropcap cropcap = {0};
        // cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        // if (-1 == xioctl (fd, VIDIOC_CROPCAP, &cropcap))
        // {
        //         perror("Querying Cropping Capabilities");
        //         return 1;
        // }
 
        // printf( "Camera Cropping:\n"
        //         "  Bounds: %dx%d+%d+%d\n"
        //         "  Default: %dx%d+%d+%d\n"
        //         "  Aspect: %d/%d\n",
        //         cropcap.bounds.width, cropcap.bounds.height, cropcap.bounds.left, cropcap.bounds.top,
        //         cropcap.defrect.width, cropcap.defrect.height, cropcap.defrect.left, cropcap.defrect.top,
        //         cropcap.pixelaspect.numerator, cropcap.pixelaspect.denominator);
 
        int support_grbg10 = 0;
 
        struct v4l2_fmtdesc fmtdesc = {0};
        fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        char fourcc[5] = {0};
        char c, e;
        printf("  FMT : CE Desc\n--------------------\n");
        while (0 == xioctl(fd, VIDIOC_ENUM_FMT, &fmtdesc))
        {
                strncpy(fourcc, (char *)&fmtdesc.pixelformat, 4);
                if (fmtdesc.pixelformat == V4L2_PIX_FMT_SGRBG10)
                    support_grbg10 = 1;
                c = fmtdesc.flags & 1? 'C' : ' ';
                e = fmtdesc.flags & 2? 'E' : ' ';
                printf("  %s: %c%c %s\n", fourcc, c, e, fmtdesc.description);
                fmtdesc.index++;
        }
        /*
        if (!support_grbg10)
        {
            printf("Doesn't support GRBG10.\n");
            return 1;
        }*/
 
        struct v4l2_format fmt = {0};
        fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        fmt.fmt.pix.width = 1280;
        fmt.fmt.pix.height = 720;
        fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_SGBRG10P;
        fmt.fmt.pix.field = V4L2_FIELD_NONE;
        
        if (-1 == xioctl(fd, VIDIOC_S_FMT, &fmt))
        {
            perror("Setting Pixel Format");
            return 1;
        }
 
        strncpy(fourcc, (char *)&fmt.fmt.pix.pixelformat, 4);
        printf( "Selected Camera Mode:\n"
                "  Width: %d\n"
                "  Height: %d\n"
                "  PixFmt: %s\n"
                "  Field: %d\n",
                fmt.fmt.pix.width,
                fmt.fmt.pix.height,
                fourcc,
                fmt.fmt.pix.field);
        return 0;
}
 
int init_mmap(int fd)
{
    struct v4l2_requestbuffers req = {0};
    req.count = 1;
    req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    req.memory = V4L2_MEMORY_MMAP;
 
    if (-1 == xioctl(fd, VIDIOC_REQBUFS, &req))
    {
        perror("Requesting Buffer");
        return 1;
    }
 
    struct v4l2_buffer buf = {0};
    buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    buf.memory = V4L2_MEMORY_MMAP;
    buf.index = 0;
    if(-1 == xioctl(fd, VIDIOC_QUERYBUF, &buf))
    {
        perror("Querying Buffer");
        return 1;
    }
 
    buffer = (uint8_t*)mmap (NULL, buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, buf.m.offset);
    printf("Length: %d\nAddress: %p\n", buf.length, buffer);
    printf("Image Length: %d\n", buf.bytesused);
 
    return 0;
}
 
int capture_image(int fd)
{

    printf("\n Entered Capture Image Function \n\n");

    struct v4l2_buffer buf = {0};
    buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    buf.memory = V4L2_MEMORY_MMAP;
    buf.index = 0;
    if(-1 == xioctl(fd, VIDIOC_QBUF, &buf))
    {
        perror("Query Buffer");
        return 1;
    }
 
    if(-1 == xioctl(fd, VIDIOC_STREAMON, &buf.type))
    {
        perror("Start Capture");
        return 1;
    }

    int size = buf.bytesused;

 
    fd_set fds;
    FD_ZERO(&fds);
    FD_SET(fd, &fds);
    struct timeval tv = {0};
    tv.tv_sec = 2;
    int r = select(fd+1, &fds, NULL, NULL, &tv);
    printf("\n Returned from select() call \n\n");
    if(-1 == r)
    {
        perror("Waiting for Frame");
        return 1;
    }

    printf("\n Returned from frame call \n\n");
 
    // if(-1 == xioctl(fd, VIDIOC_DQBUF, &buf))
    // {
    //     perror("Retrieving Frame");
    //     return 1;
    // }

    if (-1 == ioctl(fd, VIDIOC_DQBUF, &buf))
    {
          printf("\n Entered ioctl call \n\n");
          perror("Queue Buffer");
          return 1;
    }

    printf("\n Returned from retrieving frame call \n\n");

    printf ("saving image\n");
    int file = open("output.raw", O_WRONLY);
    write(file, buffer, size);


    
    // IplImage* frame;
    // CvMat cvmat = cvMat(480, 640, CV_8UC3, (void*)buffer);
    // frame = cvDecodeImage(&cvmat, 1);
    // cvNamedWindow("window",CV_WINDOW_AUTOSIZE);
    // cvShowImage("window", frame);
    // cvWaitKey(0);
    // cvSaveImage("image.jpg", frame, 0);
 
    return 0;
}
 
int main()
{

        printf("\n Running single image acquisition\n\n");
        int fd;
 
        fd = open("/dev/video0", O_RDWR);
        if (fd == -1)
        {
                perror("Error: Opening video device");
                return 1;
        }
        if(print_caps(fd))
            return 1;
        
        if(init_mmap(fd))
            return 1;
        int i;
        for(i=0; i<5; i++)
        {
            if(capture_image(fd))
                return 1;
        }
        close(fd);
        return 0;
}

The code never returns and gets hung. I noticed 2 issues:

[1]

printf(“Image Length: %d\n”, buf.bytesused);

returns 0 which seems odd to me.
[2]

if (-1 == ioctl(fd, VIDIOC_DQBUF, &buf))
{
    printf("\n Entered ioctl call \n\n");
    perror("Queue Buffer");
    return 1;
}

The ioctl function never returns and hence the program gets stuck. This explains the behavior I am seeing.

I adapted this code from the v4l2 capture.c example so i am not too sure why I am getting this behavior. I would greatly appreciate it if someone could help me figure out what is going wrong here. Thank you :)

Hi @msingh44,

Taking a quick look into the code, I am thinking about 3 things:

  1. The pixel format, is the one set the correct one? Shouldn’t it be like RG10? I don’t recall if the format was packed or not, maybe you can try this RG10 format to check.
  2. Try simulating the controls and everything you used when using v4l2-ctl, such as the control_bypass set to 0.
  3. Check dmesg logs to see if you are not getting errors for the dequeueing (run dmesg on console)

Regards,
Roberto Gutierrez,
Embedded SW Engineer at RidgeRun
Contact us: support@ridgerun.com
Developers wiki: https://developer.ridgerun.com/

Hi Roberto,

[1] I tried to look for the RG10 version in this format V4L2_PIX_FORMAT_XXXX but cannot seem to find one that resembles RG10. Would you happen to know what the exact format is?

[2] The v4l2-ctl command I used which works is – v4l2-ctl -d /dev/video0 -csensor_mode=4 --set-fmt-video=width=1280,height=720,pixelformat=RG10 --set-ctrl bypass_mode=0 --stream-mmap --stream-count=600 --stream-to=FILE.raw . However, as mentioned earlier, when trying to stream to a raw file, the frame rate drops and so that is why I am trying to acquire it using the v4l2 api instead.

[3] Here are some messages I am getting from dmesg

// [ 730.631701] imx219 8-0010: Error writing mode

// [ 1098.648929] vi 54080000.vi: Calibrate csi port 4

// [ 1098.730635] misc tegra_camera_ctrl: tegra_camera_update_isobw: Warning, Requested ISO BW 2850000 has been capped to VI’s max BW 1500000

// [ 1098.959022] video4linux video0: frame start syncpt timeout!0

// [ 1098.964697] vi 54080000.vi: TEGRA_CSI_PIXEL_PARSER_STATUS 0x00000000

// [ 1098.964702] vi 54080000.vi: TEGRA_CSI_CIL_STATUS 0x00000000

// [ 1098.964707] vi 54080000.vi: TEGRA_CSI_CILX_STATUS 0x00000000

// [ 1098.964746] vi 54080000.vi: cil_settingtime was autocalculated

// [ 1098.964751] vi 54080000.vi: csi clock settle time: 13, cil settle time: 10

// [ 1118.512798] misc tegra_camera_ctrl: tegra_camera_update_isobw: Warning, Requested ISO BW 2493750 has been capped to VI’s max BW 1500000

// [ 1155.653191] vi 54080000.vi: Calibrate csi port 4

// [ 1156.397319] misc tegra_camera_ctrl: tegra_camera_update_isobw: Warning, Requested ISO BW 2850000 has been capped to VI’s max BW 1500000

// [ 1156.397346] vi 54080000.vi: cil_settingtime was autocalculated

// [ 1156.397352] vi 54080000.vi: csi clock settle time: 13, cil settle time: 10

// [ 1156.408051] tegra-vii2c 546c0000.i2c: no acknowledge from address 0x10

// [ 1156.414696] regmap_util_write_table_8:regmap_util_write_table:-121

// [ 1156.420720] imx219 8-0010: Error writing mode

// [ 1173.190917] vi 54080000.vi: Calibrate csi port 4

// [ 1173.272626] misc tegra_camera_ctrl: tegra_camera_update_isobw: Warning, Requested ISO BW 3206250 has been capped to VI’s max BW 1500000

// [ 1173.499020] video4linux video0: frame start syncpt timeout!0

Hi @msingh44,

  1. The format is the one defined here for RG10:
    2.9.4. V4L2_PIX_FMT_SRGGB10 (‘RG10’), V4L2_PIX_FMT_SGRBG10 (‘BA10’), V4L2_PIX_FMT_SGBRG10 (‘GB10’), V4L2_PIX_FMT_SBGGR10 (‘BG10’), — The Linux Kernel documentation.

  2. I am thinking about the controls you are passing: -csensor_mode=4 and --set-ctrl bypass_mode=0, you might need to simulate their execution in this new application you are developing, maybe that’s causing an issue. You can see an example on how to set them here: https://github.com/6by9/yavta/blob/master/yavta.c#L599. Also, it’s probable that the application you are basing yours off already have something of that implemented, in that case, you will need. In that case you will only need the ids for these two controls. You can obtain them by running

v4l2-ctl --list-ctrls

Camera Controls

                 group_hold 0x009a2003 (bool)   : default=0 value=0 flags=execute-on-write
                sensor_mode 0x009a2008 (int64)  : min=0 max=6 step=1 default=0 value=0 flags=slider
                       gain 0x009a2009 (int64)  : min=16 max=170 step=1 default=16 value=16 flags=slider
                   exposure 0x009a200a (int64)  : min=13 max=683709 step=1 default=2495 value=13 flags=slider
                 frame_rate 0x009a200b (int64)  : min=2000000 max=60000000 step=1 default=60000000 value=2000000 flags=slider
       sensor_configuration 0x009a2032 (u32)    : min=0 max=4294967295 step=1 default=0 [22] flags=read-only, volatile, has-payload
     sensor_mode_i2c_packet 0x009a2033 (u32)    : min=0 max=4294967295 step=1 default=0 [1026] flags=read-only, volatile, has-payload
  sensor_control_i2c_packet 0x009a2034 (u32)    : min=0 max=4294967295 step=1 default=0 [1026] flags=read-only, volatile, has-payload
                bypass_mode 0x009a2064 (intmenu): min=0 max=1 default=0 value=0
            override_enable 0x009a2065 (intmenu): min=0 max=1 default=0 value=0
               height_align 0x009a2066 (int)    : min=1 max=16 step=1 default=1 value=1
                 size_align 0x009a2067 (intmenu): min=0 max=2 default=0 value=0
           write_isp_format 0x009a2068 (int)    : min=1 max=1 step=1 default=1 value=1
   sensor_signal_properties 0x009a2069 (u32)    : min=0 max=4294967295 step=1 default=0 [30][18] flags=read-only, has-payload
    sensor_image_properties 0x009a206a (u32)    : min=0 max=4294967295 step=1 default=0 [30][16] flags=read-only, has-payload
  sensor_control_properties 0x009a206b (u32)    : min=0 max=4294967295 step=1 default=0 [30][36] flags=read-only, has-payload
          sensor_dv_timings 0x009a206c (u32)    : min=0 max=4294967295 step=1 default=0 [30][16] flags=read-only, has-payload
           low_latency_mode 0x009a206d (bool)   : default=0 value=0
           preferred_stride 0x009a206e (int)    : min=0 max=65535 step=1 default=0 value=0
               sensor_modes 0x009a2082 (int)    : min=0 max=30 step=1 default=30 value=6 flags=read-only

In that output, you can see bypass mode id is 0x009a2064, and sensor mode id is 0x009a2008

  1. In the log, I can see that you are not getting a response from the driver, after you try to capture, can you run:

sudo i2cset -y -f 8 0x10 0x00 0x00
sudo i2cget -y -f 8 0x10
sudo i2cget -y -f 8 0x10

To read the model ID from the camera (register addresses 0x000->0x0001). So to check the camera is still there.

Regards,
Roberto

sorry for jump in, you may refer to MMAPI sample, 12_camera_v4l2_cuda.
you may see-also [Block Diagram] for the flow of data through this sample.

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.