This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Video Capture Loopback

Other Parts Discussed in Thread: OMAP3530

Hi,

I 'm using the saMmapLoopback.c  in the DVSDK to capture video and display on the LCD. I compiled it and it could capture the video and display it correctly.

Now I  just add a time delay of two for(;;) loop like this: ( below is  saMmapLoopback.c modified and in black is my code )

********************************************************************************************************************************************************************

*******************************************************************************************************************************************************************

/*
 *
 * Copyright (C) 2007 Texas Instruments Inc
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
/*
 * File name   : saMmapLoopback.c
 * Description : Application used to do NTSC loopback in MMAP memory mode
 */
#include <stdio.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/time.h>
#include <linux/videodev.h>
#include <linux/videodev2.h>
#include </home/fc/camera_kernel/linux/include/linux/omap24xxvout.h>


/* structure used to store information of the buffers */
struct buf_info {
    int index;
    unsigned int length;
    char *start;
};

/* Changing the following will result in different number of buffers used */
#define CAPTURE_MAX_BUFFER        3
#define DISPLAY_MAX_BUFFER        3
/* device to be used for capture */
#define CAPTURE_DEVICE        "/dev/video0"
#define CAPTURE_NAME        "Capture"
/* device to be used for display */
#define DISPLAY_DEVICE        "/dev/video1"
#define DISPLAY_NAME        "Display"
/* number of frames to be captured and displayed */
#define MAXLOOPCOUNT        1000
#if 0
/* absolute path of the sysfs entry for controlling video1 to channel0 */
#define OUTPUTPATH      "/sys/class/display_control/omap_disp_control/video1"
/* absolute path of the sysfs entry for controlling channel0 to LCD */
#define OUTPUTPATH_1      "/sys/class/display_control/omap_disp_control/ch0_output"
#endif
#define WIDTH 720
#define HEIGHT 480
#define DEF_PIX_FMT        V4L2_PIX_FMT_UYVY

/* capture_buff_info and display_buff_info stores buffer information of capture
   and display respectively. */
static struct buf_info capture_buff_info[CAPTURE_MAX_BUFFER];
static struct buf_info display_buff_info[DISPLAY_MAX_BUFFER];


/*===============================initCapture==================================*/
/* This function initializes capture device. It selects an active input
 * and detects the standard on that input. It then allocates buffers in the
 * driver's memory space and mmaps them in the application space.
 */
static int initCapture(int *capture_fd, int *numbuffers, char *inputname,
                char *stdname, struct v4l2_format *fmt)
{
    int ret, i, j;
    struct v4l2_requestbuffers reqbuf;
    struct v4l2_buffer buf;
    struct v4l2_capability capability;
    struct v4l2_input input;
    v4l2_std_id std_id;
    struct v4l2_standard standard;
    int index;

    /* Open the capture device */
    *capture_fd  = open((const char *) CAPTURE_DEVICE, O_RDWR);
    if (*capture_fd  <= 0) {
        printf("Cannot open = %s device\n", CAPTURE_DEVICE);
        return -1;
    }
    printf("\n%s: Opened Channel\n", CAPTURE_NAME);

    /* Get any active input */
    if (ioctl(*capture_fd, VIDIOC_G_INPUT, &index) < 0) {
        perror("VIDIOC_G_INPUT");
        goto ERROR;
    }

    /* Enumerate input to get the name of the input detected */
    memset(&input, 0, sizeof(input));
    input.index = index;
    if (ioctl(*capture_fd, VIDIOC_ENUMINPUT, &input) < 0) {
        perror("VIDIOC_ENUMINPUT");
        goto ERROR;
    }

    printf("%s: Current Input: %s\n", CAPTURE_NAME, input.name);
    /* Store the name of the output as per the input detected */
    strcpy(inputname, (char*)input.name);

    /* Detect the standard in the input detected */
    if (ioctl(*capture_fd, VIDIOC_QUERYSTD, &std_id) < 0) {
        perror("VIDIOC_QUERYSTD");
        goto ERROR;
    }

    /* Get the standard*/
    if (ioctl(*capture_fd, VIDIOC_G_STD, &std_id) < 0) {
        /* Note when VIDIOC_ENUMSTD always returns EINVAL this
           is no video device or it falls under the USB exception,
           and VIDIOC_G_STD returning EINVAL is no error. */
        perror("VIDIOC_G_STD");
        goto ERROR;
    }

    memset(&standard, 0, sizeof(standard));
    standard.index = 0;
    while (1) {
        if (ioctl(*capture_fd, VIDIOC_ENUMSTD, &standard) < 0) {
            perror("VIDIOC_ENUMSTD");
            goto ERROR;
        }

        /* Store the name of the standard */
        if (standard.id & std_id) {
            strcpy(stdname, (char*)standard.name);
            printf("%s: Current standard: %s\n",
                   CAPTURE_NAME, standard.name);
            break;
        }
        standard.index++;
    }

    /* Check if the device is capable of streaming */
    if (ioctl(*capture_fd, VIDIOC_QUERYCAP, &capability) < 0) {
        perror("VIDIOC_QUERYCAP");
        goto ERROR;
    }
    if (capability.capabilities & V4L2_CAP_STREAMING)
        printf("%s: Capable of streaming\n", CAPTURE_NAME);
    else {
        printf("%s: Not capable of streaming\n", CAPTURE_NAME);
        goto ERROR;
    }

    fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    ret = ioctl(*capture_fd, VIDIOC_G_FMT, fmt);
    if (ret < 0) {
        perror("VIDIOC_G_FMT");
        goto ERROR;
    }

    fmt->fmt.pix.pixelformat = DEF_PIX_FMT;
    ret = ioctl(*capture_fd, VIDIOC_S_FMT, fmt);
    if (ret < 0) {
        perror("VIDIOC_S_FMT");
        goto ERROR;
    }

    ret = ioctl(*capture_fd, VIDIOC_G_FMT, fmt);
    if (ret < 0) {
        perror("VIDIOC_G_FMT");
        goto ERROR;
    }

    if (fmt->fmt.pix.pixelformat != DEF_PIX_FMT) {
        printf("%s: Requested pixel format not supported\n",
               CAPTURE_NAME);
        goto ERROR;
    }

    /* Buffer allocation
     * Buffer can be allocated either from capture driver or
     * user pointer can be used
     */
    /* Request for MAX_BUFFER input buffers. As far as Physically contiguous
     * memory is available, driver can allocate as many buffers as
     * possible. If memory is not available, it returns number of
     * buffers it has allocated in count member of reqbuf.
     * HERE count = number of buffer to be allocated.
     * type = type of device for which buffers are to be allocated.
     * memory = type of the buffers requested i.e. driver allocated or
     * user pointer */
    reqbuf.count = *numbuffers;
    reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    reqbuf.memory = V4L2_MEMORY_MMAP;
    ret = ioctl(*capture_fd, VIDIOC_REQBUFS, &reqbuf);
    if (ret < 0) {
        perror("Cannot allocate memory");
        goto ERROR;
    }
    /* Store the number of buffers actually allocated */
    *numbuffers = reqbuf.count;
    printf("%s: Number of requested buffers = %d\n", CAPTURE_NAME,
           *numbuffers);

    memset(&buf, 0, sizeof(buf));

    /* Mmap the buffers
     * To access driver allocated buffer in application space, they have
     * to be mmapped in the application space using mmap system call */
    for (i = 0; i < (*numbuffers); i++) {
        buf.type = reqbuf.type;
        buf.index = i;
        buf.memory = reqbuf.memory;
        ret = ioctl(*capture_fd, VIDIOC_QUERYBUF, &buf);
        if (ret < 0) {
            perror("VIDIOC_QUERYCAP");
            *numbuffers = i;
            goto ERROR1;
        }


        capture_buff_info[i].length = buf.length;
        capture_buff_info[i].index = i;
        capture_buff_info[i].start = mmap(NULL, buf.length,
                        PROT_READ |
                        PROT_WRITE,
                        MAP_SHARED,
                        *capture_fd,
                        buf.m.offset);

        if (capture_buff_info[i].start == MAP_FAILED) {
            printf("Cannot mmap = %d buffer\n", i);
            *numbuffers = i;
            goto ERROR1;
        }

        memset((void *) capture_buff_info[i].start, 0x80,
            capture_buff_info[i].length);
        /* Enqueue buffers
         * Before starting streaming, all the buffers needs to be
         * en-queued in the driver incoming queue. These buffers will
         * be used by thedrive for storing captured frames. */
        ret = ioctl(*capture_fd, VIDIOC_QBUF, &buf);
        if (ret < 0) {
            perror("VIDIOC_QBUF");
            *numbuffers = i + 1;
            goto ERROR1;
        }
    }

    printf("%s: Init done successfully\n\n", CAPTURE_NAME);
    return 0;

ERROR1:
    for (j = 0; j < *numbuffers; j++)
        munmap(capture_buff_info[j].start,
               capture_buff_info[j].length);
ERROR:
    close(*capture_fd);

    return -1;
}

/*===============================initDisplay==================================*/
/* This function initializes display device. It sets output and standard for
 * LCD. These output and standard are same as those detected in capture device.
 * It, then, allocates buffers in the driver's memory space and mmaps them in
 * the application space */
static int initDisplay(int *display_fd, int *numbuffers, char *stdname,
                struct v4l2_format *fmt)
{
    int ret, i, j;
    struct v4l2_requestbuffers reqbuf;
    struct v4l2_buffer buf;
    struct v4l2_capability capability;
    //int rotation;
    //char str[200];

    /* Set the video1 pipeline to channel0 overlay */
#if 0
#if 1
    strcpy(str, "echo channel0 > ");
#else
    strcpy(str, "echo channel1 > ");
#endif
    strcat(str, OUTPUTPATH);
    if (system(str)) {
        printf("Cannot set video1 pipeline to TV\n");
        exit(0);
    }
    /* Set the output of channel0 to LCD */
#if 1
    strcpy(str, "echo LCD > ");
    strcat(str, OUTPUTPATH_1);
    if (system(str)) {
        printf("Cannot set output to LCD\n");
        exit(0);
    }
#endif
#endif
    /* Open the video display device */
    *display_fd = open((const char *) DISPLAY_DEVICE, O_RDWR);
    if (*display_fd <= 0) {
        printf("Cannot open = %s device\n", DISPLAY_DEVICE);
        return -1;
    }
    printf("\n%s: Opened Channel\n", DISPLAY_NAME);

    /* Check if the device is capable of streaming */
    if (ioctl(*display_fd, VIDIOC_QUERYCAP, &capability) < 0) {
        perror("VIDIOC_QUERYCAP");
        goto ERROR;
    }

    if (capability.capabilities & V4L2_CAP_STREAMING)
        printf("%s: Capable of streaming\n", DISPLAY_NAME);
    else {
        printf("%s: Not capable of streaming\n", DISPLAY_NAME);
        goto ERROR;
    }

    /* Rotate by 90 degree so that 480x640 resolution will become 640x480 */
#if 0
    rotation = 90;
    ret = ioctl(*display_fd, VIDIOC_S_OMAP2_ROTATION, &rotation);
    if (ret < 0) {
        perror("VIDIOC_S_OMAP2_ROTATION");
        goto ERROR;
    }
#endif
    /* Get the format */
    fmt->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
    ret = ioctl(*display_fd, VIDIOC_G_FMT, fmt);
    if (ret < 0) {
        perror("VIDIOC_G_FMT");
        goto ERROR;
    }

    fmt->fmt.pix.width = WIDTH;
    fmt->fmt.pix.height = HEIGHT;
    fmt->fmt.pix.pixelformat = DEF_PIX_FMT;
    ret = ioctl(*display_fd, VIDIOC_S_FMT, fmt);
    if (ret < 0) {
        perror("VIDIOC_S_FMT");
        goto ERROR;
    }

    ret = ioctl(*display_fd, VIDIOC_G_FMT, fmt);
    if (ret < 0) {
        perror("VIDIOC_G_FMT");
        goto ERROR;
    }

    if (fmt->fmt.pix.pixelformat != DEF_PIX_FMT) {
        printf("%s: Requested pixel format not supported\n",
               CAPTURE_NAME);
        goto ERROR;
    }

    /* Buffer allocation
     * Buffer can be allocated either from capture driver or
     * user pointer can be used
     */
    /* Request for MAX_BUFFER input buffers. As far as Physically contiguous
     * memory is available, driver can allocate as many buffers as
     * possible. If memory is not available, it returns number of
     * buffers it has allocated in count member of reqbuf.
     * HERE count = number of buffer to be allocated.
     * type = type of device for which buffers are to be allocated.
     * memory = type of the buffers requested i.e. driver allocated or
     * user pointer */
    reqbuf.count = *numbuffers;
    reqbuf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
    reqbuf.memory = V4L2_MEMORY_MMAP;
    ret = ioctl(*display_fd, VIDIOC_REQBUFS, &reqbuf);
    if (ret < 0) {
        perror("Cannot allocate memory");
        goto ERROR;
    }
    /* Store the numbfer of buffers allocated */
    *numbuffers = reqbuf.count;
    printf("%s: Number of requested buffers = %d\n", DISPLAY_NAME,
           (*numbuffers));

    memset(&buf, 0, sizeof(buf));

    /* Mmap the buffers
     * To access driver allocated buffer in application space, they have
     * to be mmapped in the application space using mmap system call */
    for (i = 0; i < (*numbuffers); i++) {
        /* Query physical address of the buffers */
        buf.type = reqbuf.type;
        buf.index = i;
        buf.memory = reqbuf.memory;
        ret = ioctl(*display_fd, VIDIOC_QUERYBUF, &buf);
        if (ret < 0) {
            perror("VIDIOC_QUERYCAP");
            (*numbuffers) = i;
            goto ERROR1;
        }

        /* Mmap the buffers in application space */
        display_buff_info[i].length = buf.length;
        display_buff_info[i].index =  i;
        display_buff_info[i].start = mmap(NULL, buf.length,
                         PROT_READ |
                         PROT_WRITE,
                         MAP_SHARED,
                         *display_fd,
                         buf.m.offset);

        if (display_buff_info[i].start == MAP_FAILED) {
            printf("Cannot mmap = %d buffer\n", i);
            (*numbuffers) = i;
            goto ERROR1;
        }
        memset((void *) display_buff_info[i].start, 0x80,
               display_buff_info[i].length);

        /* Enqueue buffers
         * Before starting streaming, all the buffers needs to be
         * en-queued in the driver incoming queue. These buffers will
         * be used by thedrive for storing captured frames. */
        ret = ioctl(*display_fd, VIDIOC_QBUF, &buf);
        if (ret < 0) {
            perror("VIDIOC_QBUF");
            (*numbuffers) = i + 1;
            goto ERROR1;
        }
    }
    printf("%s: Init done successfully\n\n", DISPLAY_NAME);
    return 0;

ERROR1:
    for (j = 0; j < *numbuffers; j++)
        munmap(display_buff_info[j].start,
            display_buff_info[j].length);
ERROR:
    close(*display_fd);

    return -1;
}

int main()
{

    int i = 0;
    int ret = 0;
    struct v4l2_format capture_fmt;
    struct v4l2_format display_fmt;
    int capture_fd, display_fd;
    char inputname[15];
    char stdname[15];
    int capture_numbuffers = CAPTURE_MAX_BUFFER, display_numbuffers = DISPLAY_MAX_BUFFER;
    int a;
    struct v4l2_buffer display_buf, capture_buf;

    for(i = 0; i < CAPTURE_MAX_BUFFER; i++) {
        capture_buff_info[i].start = NULL;
    }
    for(i = 0; i < DISPLAY_MAX_BUFFER; i++) {
        display_buff_info[i].start = NULL;
    }
    /* STEP1:
     * Initialization section
     * Initialize capture and display devices.
     * Here one capture channel is opened and input and standard is
     * detected on that channel.
     * Display channel is opened with the same standard that is detected at
     * capture channel.
     * */
    ret = initCapture(&capture_fd, &capture_numbuffers, inputname,
            stdname, &capture_fmt);
    if(ret < 0) {
        printf("Error in opening capture device for channel 0\n");
        return ret;
    }

    /* open display channel */
    ret = initDisplay(&display_fd, &display_numbuffers,
              stdname, &display_fmt);
    if(ret < 0) {
        printf("Error in opening display device\n");
        goto ERROR_1;
    }

    /* run section
     * STEP2:
     * Here display and capture channels are started for streaming. After
     * this capture device will start capture frames into enqueued
     * buffers and display device will start displaying buffers from
     * the qneueued buffers */

    /* Start Streaming. on display device */
    a = V4L2_BUF_TYPE_VIDEO_OUTPUT;
    ret = ioctl(display_fd, VIDIOC_STREAMON, &a);
    if (ret < 0) {
        perror("VIDIOC_STREAMON");
        goto ERROR;
    }
    printf("%s: Stream on...\n", DISPLAY_NAME);

    /* Start Streaming. on capture device */
    a = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    ret = ioctl(capture_fd, VIDIOC_STREAMON, &a);
    if (ret < 0) {
        perror("VIDIOC_STREAMON");
        goto ERROR;
    }
    printf("%s: Stream on...\n", CAPTURE_NAME);

    /* Set the display buffers for queuing and dqueueing operation */
    display_buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
    display_buf.index = 0;
    display_buf.memory = V4L2_MEMORY_MMAP;

    /* Set the capture buffers for queuing and dqueueing operation */
    capture_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    capture_buf.index = 0;
    capture_buf.memory = V4L2_MEMORY_MMAP;

    /* One buffer is dequeued from display and capture channels.
     * Capture buffer will be copied to display buffer.
     * All two buffers are put back to respective channels.
     * This sequence is repeated in loop.
     * After completion of this loop, channels are stopped.
     */
//    for (i = 0; i < MAXLOOPCOUNT; i++) {
    while(1) {
        int h;
        char *cap_ptr, *dis_ptr;

//        printf("Loop %d\n", i);

        /* Dequeue display buffer */
        ret = ioctl(display_fd, VIDIOC_DQBUF, &display_buf);
        if (ret < 0) {
            perror("VIDIOC_DQBUF");
            goto ERROR;
        }

//        printf("1\n");

        /* Dequeue capture buffer */
        ret = ioctl(capture_fd, VIDIOC_DQBUF, &capture_buf);
        if (ret < 0) {
            perror("VIDIOC_DQBUF");
            goto ERROR;
        }

//        printf("2\n");

        cap_ptr = capture_buff_info[capture_buf.index].start;
        dis_ptr = display_buff_info[display_buf.index].start;
        for (h = 0; h < display_fmt.fmt.pix.height; h++) {
            memcpy(dis_ptr, cap_ptr, display_fmt.fmt.pix.width * 2);
            cap_ptr += capture_fmt.fmt.pix.width * 2;
            dis_ptr += display_fmt.fmt.pix.width * 2;
        }

/////////////////////////////////////////////////////////////////////////////////////////////////////////////my code////////////////////////////////////////////////////////////////////////////////////////////////////////////
int ii,jj;
for (ii=0;ii<60000;ii++)
{
 for(jj=0;jj<60;jj++);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////my code////////////////////////////////////////////////////////////////////////////////////////////////////////////

//        printf("3\n");

        ret = ioctl(capture_fd, VIDIOC_QBUF, &capture_buf);
        if (ret < 0) {
            perror("VIDIOC_QBUF");
            goto ERROR;
        }

//        printf("4\n");

        ret = ioctl(display_fd, VIDIOC_QBUF, &display_buf);
        if (ret < 0) {
            perror("VIDIOC_QBUF");
            goto ERROR;
        }
        
//        printf("5\n");
    }

    a = V4L2_BUF_TYPE_VIDEO_OUTPUT;
    ret = ioctl(display_fd, VIDIOC_STREAMOFF, &a);
    if (ret < 0) {
        perror("VIDIOC_STREAMOFF");
        goto ERROR;
    }
    printf("\n%s: Stream off!!\n", DISPLAY_NAME);

    a = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    ret = ioctl(capture_fd, VIDIOC_STREAMOFF, &a);
    if (ret < 0) {
        perror("VIDIOC_STREAMOFF");
        goto ERROR;
    }
    printf("%s: Stream off!!\n", CAPTURE_NAME);

    printf("\nLoopback Successful\n\n");

ERROR:
    /* Un-map the buffers */
    for (i = 0; i < display_numbuffers; i++) {
        munmap(display_buff_info[i].start,
               display_buff_info[i].length);
        display_buff_info[i].start = NULL;
    }
    /* Close the file handle */
    close(display_fd);

ERROR_1:
    /* Un-map the buffers */
    for (i = 0; i < capture_numbuffers; i++) {
        munmap(capture_buff_info[i].start,
               capture_buff_info[i].length);
        capture_buff_info[i].start = NULL;
    }
    /* Close the file handle */
    close(capture_fd);

    return 0;
}

*******************************************************************************************************************************************************************

*******************************************************************************************************************************************************************

Then the program could run for 2-3 seconds and then stopped. It could capture about 50 frames. I found that the longer of the time delay is ,  the fewer it could capture.

I think it doesn't matter how long it cost in each while loop because the program was run in order. Maybe it wouldn't be  smooth but it shouldn't stop.

 

Please advice, thanks

  • This sounds like it could be a problem with the driver, what version of the PSP are you using? The current version available here is PSP 2.01.03.11.

  • Hi,

    I have purchased omap3530 Dev kit 8000 recently for doing video processing.

    Application ::  After capturing the video,I need to store in memory (pen-drive) for further processing.

     Using the command saMmapLoopback (given in the data sheet ) i am able to capture video from camera and display it on the LCD in the angstrom platform.

    i am very much new to the omap 3530 platform so can anyone tell me or guide me as to which code is to be tweaked (is it saMmapLoopback.c?).

    Any kind of suggestions and guidance are most welcome. Many thanks in advance.   

    Regards

    Prashanth