1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188
|
/*
* How to test v4l2loopback:
* 1. launch this test program (even in background), it will initialize the
* loopback device and keep it open so it won't loose the settings.
* 2. Feed the video device with data according to the settings specified
* below: size, pixelformat, etc.
* For instance, you can try the default settings with this command:
* mencoder video.avi -ovc raw -nosound -vf scale=640:480,format=yuy2 -o /dev/video1
* TODO: a command that limits the fps would be better :)
*
* Test the video in your favourite viewer, for instance:
* luvcview -d /dev/video1 -f yuyv
*/
#include <linux/videodev2.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <assert.h>
#define ROUND_UP_2(num) (((num)+1)&~1)
#define ROUND_UP_4(num) (((num)+3)&~3)
#define ROUND_UP_8(num) (((num)+7)&~7)
#define ROUND_UP_16(num) (((num)+15)&~15)
#define ROUND_UP_32(num) (((num)+31)&~31)
#define ROUND_UP_64(num) (((num)+63)&~63)
#if 0
# define CHECK_REREAD
#endif
#define VIDEO_DEVICE "/dev/video0"
#if 1
# define FRAME_WIDTH 640
# define FRAME_HEIGHT 480
#else
# define FRAME_WIDTH 512
# define FRAME_HEIGHT 512
#endif
#if 0
# define FRAME_FORMAT V4L2_PIX_FMT_YUYV
#else
# define FRAME_FORMAT V4L2_PIX_FMT_YVU420
#endif
static int debug = 0;
int format_properties(const unsigned int format,
const unsigned int width,
const unsigned int height,
size_t*linewidth,
size_t*framewidth) {
size_t lw, fw;
switch(format) {
case V4L2_PIX_FMT_YUV420: case V4L2_PIX_FMT_YVU420:
lw = width; /* ??? */
fw = ROUND_UP_4 (width) * ROUND_UP_2 (height);
fw += 2 * ((ROUND_UP_8 (width) / 2) * (ROUND_UP_2 (height) / 2));
break;
case V4L2_PIX_FMT_UYVY: case V4L2_PIX_FMT_Y41P: case V4L2_PIX_FMT_YUYV: case V4L2_PIX_FMT_YVYU:
lw = (ROUND_UP_2 (width) * 2);
fw = lw * height;
break;
default:
return 0;
}
if(linewidth)*linewidth=lw;
if(framewidth)*framewidth=fw;
return 1;
}
void print_format(struct v4l2_format*vid_format) {
printf(" vid_format->type =%d\n", vid_format->type );
printf(" vid_format->fmt.pix.width =%d\n", vid_format->fmt.pix.width );
printf(" vid_format->fmt.pix.height =%d\n", vid_format->fmt.pix.height );
printf(" vid_format->fmt.pix.pixelformat =%d\n", vid_format->fmt.pix.pixelformat);
printf(" vid_format->fmt.pix.sizeimage =%d\n", vid_format->fmt.pix.sizeimage );
printf(" vid_format->fmt.pix.field =%d\n", vid_format->fmt.pix.field );
printf(" vid_format->fmt.pix.bytesperline=%d\n", vid_format->fmt.pix.bytesperline );
printf(" vid_format->fmt.pix.colorspace =%d\n", vid_format->fmt.pix.colorspace );
}
int main(int argc, char**argv)
{
struct v4l2_capability vid_caps;
struct v4l2_format vid_format;
size_t framesize = 0;
size_t linewidth = 0;
__u8*buffer;
__u8*check_buffer;
const char*video_device=VIDEO_DEVICE;
int fdwr = 0;
int ret_code = 0;
int i;
if(argc>1) {
video_device=argv[1];
printf("using output device: %s\n", video_device);
}
fdwr = open(video_device, O_RDWR);
assert(fdwr >= 0);
ret_code = ioctl(fdwr, VIDIOC_QUERYCAP, &vid_caps);
assert(ret_code != -1);
memset(&vid_format, 0, sizeof(vid_format));
ret_code = ioctl(fdwr, VIDIOC_G_FMT, &vid_format);
if(debug)print_format(&vid_format);
vid_format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
vid_format.fmt.pix.width = FRAME_WIDTH;
vid_format.fmt.pix.height = FRAME_HEIGHT;
vid_format.fmt.pix.pixelformat = FRAME_FORMAT;
vid_format.fmt.pix.sizeimage = framesize;
vid_format.fmt.pix.field = V4L2_FIELD_NONE;
vid_format.fmt.pix.bytesperline = linewidth;
vid_format.fmt.pix.colorspace = V4L2_COLORSPACE_SRGB;
if(debug)print_format(&vid_format);
ret_code = ioctl(fdwr, VIDIOC_S_FMT, &vid_format);
assert(ret_code != -1);
if(debug)printf("frame: format=%d\tsize=%lu\n", FRAME_FORMAT, framesize);
print_format(&vid_format);
if(!format_properties(vid_format.fmt.pix.pixelformat,
vid_format.fmt.pix.width, vid_format.fmt.pix.height,
&linewidth,
&framesize)) {
printf("unable to guess correct settings for format '%d'\n", FRAME_FORMAT);
}
buffer=(__u8*)malloc(sizeof(__u8)*framesize);
check_buffer=(__u8*)malloc(sizeof(__u8)*framesize);
memset(buffer, 0, framesize);
memset(check_buffer, 0, framesize);
for (i = 0; i < framesize; ++i) {
//buffer[i] = i % 2;
check_buffer[i] = 0;
}
write(fdwr, buffer, framesize);
#ifdef CHECK_REREAD
do {
/* check if we get the same data on output */
int fdr = open(video_device, O_RDONLY);
read(fdr, check_buffer, framesize);
for (i = 0; i < framesize; ++i) {
if (buffer[i] != check_buffer[i])
assert(0);
}
close(fdr);
} while(0);
#endif
pause();
close(fdwr);
free(buffer);
free(check_buffer);
return 0;
}
|