/*
* UVC gadget test application
*
* Copyright (C) 2010 Ideas on board SPRL <laurent.pinchart@ideasonboard.com>
*
* 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.,
*/
#include <sys/time.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/select.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <errno.h>
#include <linux/usb/ch9.h>
#include <linux/usb/video.h>
#include <linux/videodev2.h>
#include "uvc.h"
//#include "./drivers/usb/gadget/function/uvc.h"
#define clamp(val, min, max) ({ \
typeof(val) __val = (val); \
typeof(min) __min = (min); \
typeof(max) __max = (max); \
(void) (&__val == &__min); \
(void) (&__val == &__max); \
__val = __val < __min ? __min: __val; \
__val > __max ? __max: __val; })
#define ARRAY_SIZE(a) ((sizeof(a) / sizeof(a[0])))
struct uvc_device
{
int fd;
struct uvc_streaming_control probe;
struct uvc_streaming_control commit;
int control;
unsigned int fcc;
unsigned int width;
unsigned int height;
void** mem;
unsigned int nbufs;
unsigned int bufsize;
unsigned int bulk;
uint8_t color;
unsigned int imgsize;
void* imgdata;
int startFlag;
};
//#define NV12 1
#define DYNAMIC_MJPEG 1
#define jjg_printf(fmt, ...) \
printf("==jjg %s[%d]" fmt, __func__, __LINE__, ##__VA_ARGS__)
#define TEST_DELAY_TIME (30 * 1000)
#define MJPEG_FILE_PATH "./MJPEG/"
#define MAX_FRAME_SIZE 4*1024*1024
#define PICTURE_NUM 1//200//(8)
int uvc_stream_start = 0;
char *PictureBuff[PICTURE_NUM];
int PictureBuffSize[PICTURE_NUM];
int frame_count = 0;
int picture_count = 0;
static struct uvc_device*
uvc_open(const char* devname)
{
struct uvc_device* dev;
struct v4l2_capability cap;
int ret;
int fd;
fd = open(devname, O_RDWR | O_NONBLOCK);
if (fd == -1)
{
printf("v4l2 open failed: %s (%d)\n", strerror(errno), errno);
return NULL;
}
printf("open succeeded, file descriptor = %d\n", fd);
ret = ioctl(fd, VIDIOC_QUERYCAP, &cap);
if (ret < 0)
{
printf("unable to query device: %s (%d)\n", strerror(errno),
errno);
close(fd);
return NULL;
}
printf("device is %s on bus %s\n", cap.card, cap.bus_info);
printf("[uvc device cap]:\n\
driver:%s\n\
card:%s\n\
bus_info:%s\n\
version:%d\n\
cap:%x\n\
devcaps:%x\n", cap.driver,
cap.card,
cap.bus_info,
cap.version,
cap.capabilities,
cap.device_caps
);
dev = (struct uvc_device*)malloc(sizeof * dev);
if (dev == NULL)
{
close(fd);
return NULL;
}
memset(dev, 0, sizeof * dev);
dev->fd = fd;
return dev;
}
static void
uvc_close(struct uvc_device* dev)
{
int i;
close(dev->fd);
free(dev->imgdata);
free(dev->mem);
free(dev);
for (i = 0; i < PICTURE_NUM ; i++)
free(PictureBuff[i]);
}
/* ---------------------------------------------------------------------------
* Video streaming
*/
#define HI_U16 int
#define HI_U32 int
void debug_dump(char *buffer, HI_U16 length, char *pDescription)
{
char stream[60];
char byteOffsetStr[10];
int i;
int offset, count, byteOffset;
printf("<-----------Dumping %d Bytes : %s -------->\n", length, pDescription);
//A_PRINTF("%s:%d = \n", pDescription, length);
count = 0;
offset = 0;
byteOffset = 0;
for(i = 0; i < length; i++) {
sprintf(stream + offset, "%2.2X ", buffer[i]);
count ++;
offset += 3;
if(count == 16) {
count = 0;
offset = 0;
sprintf(byteOffsetStr,"%4.4X",byteOffset);
printf("[%s]: %s\n", byteOffsetStr, stream);
memset(stream, 0, 60);
byteOffset += 16;
}
}
if(offset != 0) {
sprintf(byteOffsetStr,"%4.4X",byteOffset);
printf("[%s]: %s\n", byteOffsetStr, stream);
}
printf("<------------------------------------------------->\n");
}
static void
uvc_video_fill_buffer(struct uvc_device* dev, struct v4l2_buffer* buf)
{
unsigned int bpl;
unsigned int i;
unsigned int *pbuf;
char *tmpbuf;
switch (dev->fcc)
{
#ifdef NV12
case V4L2_PIX_FMT_NV12:
bpl = dev->width * 3 / 2;
for (i = 0; i < dev->height; ++i)
memset(dev->mem[buf->index] + i*bpl, dev->color++, bpl);
buf->bytesused = bpl * dev->height;
break;
#endif
case V4L2_PIX_FMT_YUYV:
bpl = dev->width * 2;
for (i = 0; i < dev->height; ++i)
memset(dev->mem[buf->index] + i*bpl, dev->color++, bpl);
buf->bytesused = bpl * dev->height;
break;
case V4L2_PIX_FMT_MJPEG:
memcpy(dev->mem[buf->index], PictureBuff[picture_count], PictureBuffSize[picture_count]);
buf->bytesused = PictureBuffSize[picture_count];
#ifdef DYNAMIC_MJPEG
buf->bytesused += (int)(rand()/(RAND_MAX + 1.0) * 1024 * 100); //模拟MJPEG体积变化
#endif
frame_count ++;
{
picture_count++;
if(picture_count >= PICTURE_NUM)
picture_count = 0;
}
//printf("(int)(rand()/(RAND_MAX + 1.0) * 1024 * 1024):%d\n",(int)(rand()/(RAND_MAX + 1.0) * 1024));
printf("buf->bytesused:%d\n", buf->bytesused);
break;
}
}
static int
uvc_video_process(struct uvc_device* dev)
{
struct v4l2_buffer buf;
int ret;
static int32_t delayTestCnt = 0;
if(dev->startFlag == 0)
{
return 0; //not start yet.
}
#if 0
delayTestCnt++;
if(delayTestCnt%100 != 0)
{
//printf("%s[%d] Currently No Frame Valid\n", __FUNCTION__, __LINE__);
usleep(10000);
return 0;
}
#endif
memset(&buf, 0, sizeof buf);
buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
buf.memory = V4L2_MEMORY_MMAP;
#if 1
memset(&buf, 0, sizeof buf);
buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
buf.memory = V4L2_MEMORY_MMAP;
if ((ret = ioctl(dev->fd, VIDIOC_DQBUF, &buf)) < 0) {
//printf("Unable to dequeue buffer: %s (%d), ret:%d.\n", strerror(errno),
// errno, ret);
return ret;
}
#endif
uvc_video_fill_buffer(dev, &buf);
if ((ret = ioctl(dev->fd, VIDIOC_QBUF, &buf)) < 0) {
printf("Unable to requeue buffer: %s (%d).\n", strerror(errno),
errno);
return ret;
}
//usleep(TEST_DELAY_TIME);
return 0;
}
static int
uvc_video_reqbufs(struct uvc_device* dev, int nbufs)
{
struct v4l2_requestbuffers rb;
struct v4l2_buffer buf;
unsigned int i;
int ret;
for (i = 0; i < dev->nbufs; ++i)
{ munmap(dev->mem[i], dev->bufsize); }
free(dev->mem);
dev->mem = 0;
dev->nbufs = 0;