首先感谢阅读,如果您也对TDA4相关的开发感兴趣,我们这边有个学习交流微信群,可以入群和大家一起交流学习。

资历较浅,水平有限,如遇错误,请大家多指正!

保持开源精神,共同分享、进步!

博主WX : AIR_12  我会拉你入群。

链接:TDA4 相关专栏        链接:TDA4  Demo  Gitee开源库

欢迎大家加入,一起维护这个开源库,给更多的朋友提供帮助。


        因为公司使用的TDA4开发板目前没有提供LVDS接口的摄像头,所以我们只能先使用USB摄像头获取YUV数据,用来调试。这里和小伙伴们分享以下如何通过USB摄像头获取YUV的数据。


        USB摄像头使用的V4L2的协议,Video for Linux 2.0 版本。(USB摄像头要支持YUYV图像输出格式)

        可以直接将此工程放入TI SDK 0800版本的vision_apps内进行编译。完成工程下载地址:

https://download.csdn.net/download/AIRKernel/36113518

效果如下图:

1、将USB摄像头连接到开发板上,如图:

 2、登录到开发板,设备会被挂载到/dev/ 下,使用ls -l查看一下

开发板默认好像有一个video0,所以我们这里使用video1。

3、 下面是完整代码,需要分为三个文件,大家可以拷贝到两个文件,然后自己试一下。

外部调用一个usb_camera_init、然后运行usb_camera_running,即可获取YUYV图像。

程序内提供了YUYV图像转I420格式;I420格式转NV12格式的格式转换功能,大家可以自行参考。

比较简单,直接上代码了。希望对大家有帮助!


生成的 saved.yuyv 文件为 i420格式,可以使用Ubuntu 的mplayer进行查看。

w和摄像头设置的WIDTH相同;h和摄像头设置的HEIGHT相同。

format可以根据不同的图片格式选择不同的格式。后面的loop 0 表示循环播放。大家自行摸索一下。

mplayer -demuxer rawvideo -rawvideo w=1280:h=720:format=i420 saved.yuyv -loop 0


usb_camera.husb_camera.c
usb_camera_file_save.husb_camera_file_save.c

formatConverter.h

formatConverter.c

第一个文件,主程序:

头文件:


#ifndef __APP_USB_CAMERA_H__
#define __APP_USB_CAMERA_H__
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <linux/videodev2.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>

#define TRUE 1
#define FALSE 0

#define FILE_VIDEO "/dev/video1"
#define YUV "/home/root/image_yuv.yuyv"
#define YUV420 "/home/root/converter.yuv"

#define IMAGEWIDTH 1280
#define IMAGEHEIGHT 720

extern FILE *fp2, *fp3;

extern char *pmap;
extern char *pmap420;
int init_v4l2(void);
int v4l2_grab(void);
int close_v4l2(void);
int app_usb_camera(void);
int usb_camera_init(void);
void usb_camera_running(void);

#endif

源文件:


#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <linux/videodev2.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include "usb_camera.h"
#include "usb_camera_file_save.h"
#include "formatConverter.h"

static int fd;
static struct v4l2_capability cap;
struct v4l2_fmtdesc fmtdesc;
struct v4l2_format fmt, fmtack;
struct v4l2_streamparm setfps;
struct v4l2_requestbuffers req;
struct v4l2_buffer buf;
enum v4l2_buf_type type;
//unsigned char frame_buffer[IMAGEWIDTH * IMAGEHEIGHT * 3];
FORMAT_CONVERTER_DEF format;
char *pmap;
char *pmap420;
void yuvI420ToNV12(char *I420, char *NV12, int width, int height);
//FILE *fp3;
struct buffer
{
    void *start;
    unsigned int length;
} * buffers;

int init_v4l2(void)
{
    //opendev
    if ((fd = open(FILE_VIDEO, O_RDWR)) == -1)
    {
        printf("Error opening V4L interface\n");
        return (FALSE);
    }

    //query cap
    if (ioctl(fd, VIDIOC_QUERYCAP, &cap) == -1) /* 获取设备支持的操作 */
    {
        printf("Error opening device %s: unable to query device.\n", FILE_VIDEO);
        return (FALSE);
    }
    else
    {
        printf("driver:\t\t%s\n", cap.driver);
        printf("card:\t\t%s\n", cap.card);
        printf("bus_info:\t%s\n", cap.bus_info);
        printf("version:\t%d\n", cap.version);
        printf("capabilities:\t%x\n", cap.capabilities);

        if ((cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) == V4L2_CAP_VIDEO_CAPTURE)
        {
            printf("Device %s: supports capture.\n", FILE_VIDEO);
        }

        if ((cap.capabilities & V4L2_CAP_STREAMING) == V4L2_CAP_STREAMING)
        {
            printf("Device %s: supports streaming.\n", FILE_VIDEO);
        }
    }

    //emu all support fmt
    fmtdesc.index = 0;
    fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    printf("Support format:\n");
    while (ioctl(fd, VIDIOC_ENUM_FMT, &fmtdesc) != -1) // 列举设备所支持的格式
    {
        printf("\t%d.%s\n", fmtdesc.index + 1, fmtdesc.description);
        fmtdesc.index++;
    }

    //set fmt
    fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
    fmt.fmt.pix.height = IMAGEHEIGHT;
    fmt.fmt.pix.width = IMAGEWIDTH;
    fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;

    if (ioctl(fd, VIDIOC_S_FMT, &fmt) == -1) /* 设置捕获视频的格式 */
    {
        printf("Unable to set format\n");
        return FALSE;
    }
    if (ioctl(fd, VIDIOC_G_FMT, &fmt) == -1) /* 获取设置支持的视频格式 */
    {
        printf("Unable to get format\n");
        return FALSE;
    }
    {
        printf("fmt.type:\t\t%d\n", fmt.type);
        printf("pix.pixelformat:\t%c%c%c%c\n", fmt.fmt.pix.pixelformat & 0xFF, (fmt.fmt.pix.pixelformat >> 8) & 0xFF, (fmt.fmt.pix.pixelformat >> 16) & 0xFF, (fmt.fmt.pix.pixelformat >> 24) & 0xFF);
        printf("pix.height:\t\t%d\n", fmt.fmt.pix.height);
        printf("pix.width:\t\t%d\n", fmt.fmt.pix.width);
        printf("pix.field:\t\t%d\n", fmt.fmt.pix.field);
    }
    //set fps
    setfps.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    setfps.parm.capture.timeperframe.numerator = 10;
    setfps.parm.capture.timeperframe.denominator = 10;

    pmap = malloc(IMAGEWIDTH * IMAGEHEIGHT * 3 / 2);
    memset(pmap, 0, IMAGEWIDTH * IMAGEHEIGHT * 3 / 2);

    pmap420 = malloc(IMAGEWIDTH * IMAGEHEIGHT * 3 / 2);
    memset(pmap420, 0, IMAGEWIDTH * IMAGEHEIGHT * 3 / 2);


    printf("init %s \t[OK]\n", FILE_VIDEO);

    return TRUE;
}

int v4l2_grab(void)
{
    unsigned int n_buffers;

    //request for 4 buffers
    req.count = 4;
    req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    req.memory = V4L2_MEMORY_MMAP;
    if (ioctl(fd, VIDIOC_REQBUFS, &req) == -1) /* 向驱动提出申请内存的请求 */

    {
        printf("request for buffers error\n");
    }

    //mmap for buffers
    buffers = malloc(req.count * sizeof(*buffers));
    if (!buffers)
    {
        printf("Out of memory\n");
        return (FALSE);
    }

    for (n_buffers = 0; n_buffers < req.count; n_buffers++)
    {
        buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        buf.memory = V4L2_MEMORY_MMAP;
        buf.index = n_buffers;
        //query buffers
        if (ioctl(fd, VIDIOC_QUERYBUF, &buf) == -1) /* 向驱动查询申请到的内存 */
        {
            printf("query buffer error\n");
            return (FALSE);
        }

        buffers[n_buffers].length = buf.length;
        //map
        buffers[n_buffers].start = mmap(NULL, buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, buf.m.offset);
        if (buffers[n_buffers].start == MAP_FAILED)
        {
            printf("buffer map error\n");
            return (FALSE);
        }
    }

    //queue
    for (n_buffers = 0; n_buffers < req.count; n_buffers++)
    {
        buf.index = n_buffers;
        ioctl(fd, VIDIOC_QBUF, &buf); /* 将空闲的内存加入可捕获视频的队列 */
    }

    type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    ioctl(fd, VIDIOC_STREAMON, &type); /* 打开视频流 */

    //    ioctl(fd, VIDIOC_DQBUF, &buf); /* 将已经捕获好视频的内存拉出已捕获视频的队列 */

    printf("grab yuyv OK\n");
    return (TRUE);
}

int close_v4l2(void)
{
    ioctl(fd, VIDIOC_STREAMOFF, &cap); /* 关闭视频流 */
    if (fd != -1)
    {
        close(fd);
        return (TRUE);
    }
    return (FALSE);
}

int usb_camera_init(void)
{
    if (init_v4l2() == FALSE)
    {
        return FALSE;
    }

    printf("\nADDInfo:    usbCamera init ok!\n");

    v4l2_grab();

    return TRUE;
}

void usb_camera_delete(void)
{
    close_v4l2();
}

void usb_camera_running(void)
{

    memset(&buf, 0, sizeof(buf));
    buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    buf.memory = V4L2_MEMORY_MMAP;
    ioctl(fd, VIDIOC_DQBUF, &buf); /* 将已经捕获好视频的内存拉出已捕获视频的队列 */
    ioctl(fd, VIDIOC_QBUF, &buf);  /* 将空闲的内存加入可捕获视频的队列 */

    //设置格式转换相关
    format.inbuf = buffers[buf.index].start;
    format.outbuf = pmap420;
    format.width = IMAGEWIDTH;
    format.height = IMAGEHEIGHT;

    yuyv2yuv420(&format);

    usb_camera_file_save(&format);

    yuvI420ToNV12(pmap420,pmap,IMAGEWIDTH,IMAGEHEIGHT);

    // FILE *pic_fd = fopen("/opt/vision_apps/test_data/psdkra/tidl_demo_images/0000000501.yuv", "r+");
    // if(pic_fd)
    // {
    //     int size_read = fread(pmap, 1, (1024 * 512 * 3) / 2, pic_fd);
    //     if (size_read!=(1024*512*3)/2)
    //         return;
    // }
    // fclose(pic_fd);
//    printf("\nADDInfo:    usbCamera running ok!\n");
}



void yuvI420ToNV12(char *I420, char *NV12, int width, int height)
{
    int ySize = width * height;
    int yuvSize = width * height * 3 / 2;
    int uIdx = ySize;
    int vIdx = ySize * 5 / 4;

    memcpy(NV12, I420, ySize);

    for (int i = ySize; i < yuvSize; i += 2) {
        *(NV12 + i) = *(I420 + uIdx++);
        *(NV12 + i + 1) = *(I420 + vIdx++);
    }
}

第二个文件:格式转换

头文件:


#ifndef __FORMAT_CONVERTER_H__
#define __FORMAT_CONVERTER_H__

#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <linux/videodev2.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>

#include <stdint.h>
#include <stdbool.h>

typedef struct FormatConverter
{
    char *outbuf;
    char *inbuf;
    uint32_t height;
    uint32_t width;
} FORMAT_CONVERTER_DEF;

void yuyv2yuv420(FORMAT_CONVERTER_DEF *format);
//void yuyv2yuv420(char *inbuf, char *outbuf, uint32_t height, uint32_t width);
#endif

 源文件:

#include "formatConverter.h"

void yuyv2yuv420(FORMAT_CONVERTER_DEF *format)
{
    char *y = NULL;
    char *u = NULL;
    char *v = NULL;
    int u_c = 0;
    int v_c = 0;

    y = format->outbuf;
    u = y + format->height * format->width;
    v = u + format->height * format->width / 4;
    bool swith = true;

    uint32_t i = 0, j = 0;

    for (i = 0; i < (format->height * format->width * 2); i += 2)
    {
        *y++ = format->inbuf[i];
    }

    for (i = 0; i < format->height; i += 2)
    {
        for (j = 1; j < format->width << 1; j += 2)
        {
            if (swith)
            {
                *u++ = ((uint8_t *)(format->inbuf + (i * (format->width << 1))))[j];
                swith = false;
                u_c++;
            }
            else
            {
                *v++ = ((uint8_t *)(format->inbuf + (i * (format->width << 1))))[j];
                swith = true;
                v_c++;
            }
        }
    }
}

第三个文件:图像保存

头文件:


#ifndef __USB_CAMERA_FILE_SAVE_H__
#define __USB_CAMERA_FILE_SAVE_H__
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <linux/videodev2.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>

#include <sys/ioctl.h>
#include <stdint.h>
#include <stdbool.h>
#define DES_TO_SAVE     "/home/root/"
#define TO_SAVE_NAME    "saved.yuyv"

#include "formatConverter.h"

int usb_camera_file_save(FORMAT_CONVERTER_DEF *image);

#endif

源文件


#include "usb_camera_file_save.h"


FILE *usb_fd ;

int usb_camera_file_save(FORMAT_CONVERTER_DEF *image)
{
    int counter = 0;
    char *file_name;
    file_name=malloc(256);

    memset(file_name,0,256);

    sprintf(file_name,"%s%s",DES_TO_SAVE,TO_SAVE_NAME);

    usb_fd = fopen(file_name, "w+");

    if ( usb_fd == NULL)       //打开二进制代码,允许读写(创建)
    {
        printf("Error opening %s\n",file_name);
        free(file_name);
        return (-1);
    }

    counter = fwrite(image->outbuf, 1, image->height * image->width * 3 / 2, usb_fd);
    if(counter!=image->height * image->width * 3 / 2)
    {
        printf("Error writing %s\n",file_name);
        fclose(usb_fd);
        free(file_name);
        return -1;
    }
    fclose(usb_fd);
    free(file_name);
    return 0;
}

【声明】
【欢迎转载转发,请注明出处。原创比较辛苦,请尊重原创,祝大家学习愉快!】
【博主专注嵌入式开发,具有多年嵌入式软、硬件开发经验,欢迎大家学习交流!】
【如有嵌入式相关项目需求,欢迎私信】

Logo

更多推荐