├── Makefile ├── README.md ├── test.c ├── v4l2loopback.c └── vm_dump_test ├── .cproject ├── .project ├── Makefile ├── Makefile_o ├── MediaSample.hpp ├── V4l2Capture.cpp ├── V4l2Capture.d ├── V4l2Capture.hpp ├── V4l2CaptureInterface.cpp ├── V4l2CaptureInterface.d ├── V4l2CaptureInterface.h ├── debugging.hpp ├── libzxwcapture.a ├── main.cpp ├── main.d ├── uvcvideo.h ├── vm.c └── yuy2_dump.bin /Makefile: -------------------------------------------------------------------------------- 1 | KERNEL_DIR ?= /home/android/out/obj/KERNEL_OBJ 2 | PWD := $(shell pwd) 3 | obj-m := v4l2loopback.o 4 | CCPATH := ${ANDROID_NDK}/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86_64/bin 5 | 6 | MODULE_OPTIONS = devices=2 7 | 8 | ########################################## 9 | # note on build targets 10 | # 11 | # module-assistant makes some assumptions about targets, namely 12 | # : must be present and build the module 13 | # .ko is not enough 14 | # install: must be present (and should only install the module) 15 | # 16 | # we therefore make a .PHONY alias to .ko 17 | # and remove utils-installation from 'install' 18 | # call 'make install-all' if you want to install everything 19 | ########################################## 20 | 21 | 22 | .PHONY: all clean 23 | 24 | # we don't control the .ko file dependencies, as it is done by kernel 25 | # makefiles. therefore v4l2loopback.ko is a phony target actually 26 | .PHONY: v4l2loopback.ko 27 | 28 | all: v4l2loopback.ko 29 | v4l2loopback: v4l2loopback.ko 30 | v4l2loopback.ko: 31 | @echo "Building v4l2-loopback driver..." 32 | $(MAKE) ARCH=arm CROSS_COMPILE=$(CCPATH)/arm-linux-androideabi- -C $(KERNEL_DIR) M=$(PWD) modules 33 | 34 | 35 | clean: 36 | rm -f *~ 37 | rm -f Module.symvers Module.markers modules.order 38 | $(MAKE) -C $(KERNEL_DIR) M=$(PWD) clean 39 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | v4l2virtualdevice_android 2 | ========================= 3 | 4 | v4l2loopback for android, https://github.com/umlaeute/v4l2loopback.git 5 | 6 | test module: write yuv data to virtual video device and read yuv data from it 7 | -------------------------------------------------------------------------------- /test.c: -------------------------------------------------------------------------------- 1 | /* 2 | * How to test v4l2loopback: 3 | * 1. launch this test program (even in background), it will initialize the 4 | * loopback device and keep it open so it won't loose the settings. 5 | * 2. Feed the video device with data according to the settings specified 6 | * below: size, pixelformat, etc. 7 | * For instance, you can try the default settings with this command: 8 | * mencoder video.avi -ovc raw -nosound -vf scale=640:480,format=yuy2 -o /dev/video1 9 | * TODO: a command that limits the fps would be better :) 10 | * 11 | * Test the video in your favourite viewer, for instance: 12 | * luvcview -d /dev/video1 -f yuyv 13 | */ 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #define ROUND_UP_2(num) (((num)+1)&~1) 30 | #define ROUND_UP_4(num) (((num)+3)&~3) 31 | #define ROUND_UP_8(num) (((num)+7)&~7) 32 | #define ROUND_UP_16(num) (((num)+15)&~15) 33 | #define ROUND_UP_32(num) (((num)+31)&~31) 34 | #define ROUND_UP_64(num) (((num)+63)&~63) 35 | 36 | 37 | 38 | 39 | #if 0 40 | # define CHECK_REREAD 41 | #endif 42 | 43 | #define VIDEO_DEVICE "/dev/video0" 44 | #if 1 45 | # define FRAME_WIDTH 640 46 | # define FRAME_HEIGHT 480 47 | #else 48 | # define FRAME_WIDTH 512 49 | # define FRAME_HEIGHT 512 50 | #endif 51 | 52 | #if 1 53 | # define FRAME_FORMAT V4L2_PIX_FMT_YUYV 54 | #else 55 | # define FRAME_FORMAT V4L2_PIX_FMT_YUV420 56 | #endif 57 | 58 | static int debug=1; 59 | 60 | 61 | int format_properties(const unsigned int format, 62 | const unsigned int width, 63 | const unsigned int height, 64 | size_t*linewidth, 65 | size_t*framewidth) { 66 | size_t lw, fw; 67 | switch(format) { 68 | case V4L2_PIX_FMT_YUV420: case V4L2_PIX_FMT_YVU420: 69 | printf("format yuv420\n"); 70 | lw = width; /* ??? */ 71 | fw = ROUND_UP_4 (width) * ROUND_UP_2 (height); 72 | fw += 2 * ((ROUND_UP_8 (width) / 2) * (ROUND_UP_2 (height) / 2)); 73 | break; 74 | case V4L2_PIX_FMT_UYVY: case V4L2_PIX_FMT_Y41P: case V4L2_PIX_FMT_YUYV: /*case V4L2_PIX_FMT_YVYU:*/ 75 | printf("format yuyv\n"); 76 | lw = (ROUND_UP_2 (width) * 2); 77 | fw = lw * height; 78 | break; 79 | default: 80 | return 0; 81 | } 82 | 83 | if(linewidth)*linewidth=lw; 84 | if(framewidth)*framewidth=fw; 85 | 86 | return 1; 87 | } 88 | 89 | 90 | void print_format(struct v4l2_format*vid_format) { 91 | printf(" vid_format->type =%d\n", vid_format->type ); 92 | printf(" vid_format->fmt.pix.width =%d\n", vid_format->fmt.pix.width ); 93 | printf(" vid_format->fmt.pix.height =%d\n", vid_format->fmt.pix.height ); 94 | printf(" vid_format->fmt.pix.pixelformat =%d\n", vid_format->fmt.pix.pixelformat); 95 | printf(" vid_format->fmt.pix.sizeimage =%d\n", vid_format->fmt.pix.sizeimage ); 96 | printf(" vid_format->fmt.pix.field =%d\n", vid_format->fmt.pix.field ); 97 | printf(" vid_format->fmt.pix.bytesperline=%d\n", vid_format->fmt.pix.bytesperline ); 98 | printf(" vid_format->fmt.pix.colorspace =%d\n", vid_format->fmt.pix.colorspace ); 99 | } 100 | 101 | void writeYV12(int devFd, __u8* buffer, size_t framesize, size_t fps) { 102 | struct timeval start; 103 | struct timeval current; 104 | struct timeval lastWriteTs; 105 | struct timeval curWriteTs; 106 | int count = 0, len; 107 | int interv_us = 1000 * 1000 / fps; 108 | const char * yv12File = "yv12.dat"; 109 | int yv12Fd = open(yv12File, O_RDWR); 110 | assert(yv12Fd >= 0); 111 | gettimeofday(&lastWriteTs, NULL); 112 | for(;;) { 113 | gettimeofday(&curWriteTs, NULL); 114 | long diff_us = (curWriteTs.tv_sec - lastWriteTs.tv_sec) * 1000000 + (curWriteTs.tv_usec - lastWriteTs.tv_usec) ; 115 | if (diff_us < interv_us) { 116 | usleep((interv_us - diff_us ) ); 117 | } 118 | //calculate fps 119 | if (count % 50 == 0) { 120 | gettimeofday(¤t, NULL); 121 | if (count == 0) gettimeofday(&start, NULL); 122 | else { 123 | long secs = (current.tv_sec - start.tv_sec) * 1000000 + (current.tv_usec - start.tv_usec); 124 | printf("input yv12, fps = %f\n", 50.0 / (secs / 1000000)); 125 | } 126 | start = current; 127 | } 128 | ++count; 129 | len = read(yv12Fd, buffer, framesize); 130 | //printf("read a frame, size:%d\n", len); 131 | if (len < framesize) { 132 | lseek(yv12Fd, 0, SEEK_SET); 133 | read(yv12Fd, buffer, framesize); 134 | } 135 | 136 | //write to video dev 137 | write(devFd, buffer, framesize); 138 | gettimeofday(&lastWriteTs, NULL); 139 | } 140 | 141 | } 142 | void writeYV12WithSelect(int devFd, __u8* buffer, size_t framesize, size_t interv_ms) { 143 | struct timeval start; 144 | struct timeval current; 145 | struct timeval lastWriteTs; 146 | struct timeval curWriteTs; 147 | int count = 0, len; 148 | fd_set fds; 149 | struct timeval tv; 150 | int r; 151 | const char * yv12File = "yv12.dat"; 152 | int yv12Fd = open(yv12File, O_RDWR); 153 | assert(yv12Fd >= 0); 154 | gettimeofday(&lastWriteTs, NULL); 155 | for(;;) { 156 | gettimeofday(&curWriteTs, NULL); 157 | long diff_ms = ((curWriteTs.tv_sec - lastWriteTs.tv_sec) * 1000000 + (curWriteTs.tv_usec - lastWriteTs.tv_usec) ) / 1000; 158 | if (diff_ms < interv_ms) { 159 | usleep((interv_ms - diff_ms) * 1000); 160 | } 161 | //calculate fps 162 | if (count % 50 == 0) { 163 | gettimeofday(¤t, NULL); 164 | if (count == 0) gettimeofday(&start, NULL); 165 | else { 166 | long secs = (current.tv_sec - start.tv_sec) * 1000000 + (current.tv_usec - start.tv_usec); 167 | printf("input yv12, fps = %f\n", 50.0 / (secs / 1000000)); 168 | } 169 | start = current; 170 | } 171 | ++count; 172 | len = read(yv12Fd, buffer, framesize); 173 | //printf("read a frame, size:%d\n", len); 174 | if (len < framesize) { 175 | lseek(yv12Fd, 0, SEEK_SET); 176 | read(yv12Fd, buffer, framesize); 177 | } 178 | 179 | FD_ZERO (&fds); 180 | FD_SET (devFd, &fds); 181 | printf("devFd: %d\n", devFd); 182 | /* Timeout. */ 183 | tv.tv_sec = 5; 184 | tv.tv_usec = 0; 185 | //LOGD("before sleep\n"); 186 | //sleep(3); 187 | //LOGD("after sleep\n"); 188 | r = select(devFd + 1, &fds, NULL, NULL, &tv); 189 | //LOGD("after select, r = %d\n", r); 190 | if (-1 == r) { 191 | if (EINTR== errno) 192 | continue; 193 | //FATAL("select failed"); 194 | printf("select failed\n"); 195 | break; 196 | } 197 | 198 | if (0 == r) { 199 | //FATAL("write frame, select timeout\n"); 200 | printf("write frame, select timeout\n"); 201 | break; 202 | } 203 | //write to video dev 204 | write(devFd, buffer, framesize); 205 | gettimeofday(&lastWriteTs, NULL); 206 | } 207 | 208 | } 209 | int main(int argc, char**argv) 210 | { 211 | struct v4l2_capability vid_caps; 212 | struct v4l2_format vid_format; 213 | 214 | size_t framesize; 215 | size_t linewidth; 216 | 217 | __u8*buffer; 218 | __u8*check_buffer; 219 | 220 | const char*video_device=VIDEO_DEVICE; 221 | int fdwr = 0; 222 | int ret_code = 0; 223 | 224 | int i; 225 | 226 | if(argc>1) { 227 | video_device=argv[1]; 228 | printf("using output device: %s\n", video_device); 229 | } 230 | 231 | fdwr = open(video_device, O_RDWR); 232 | assert(fdwr >= 0); 233 | 234 | ret_code = ioctl(fdwr, VIDIOC_QUERYCAP, &vid_caps); 235 | assert(ret_code != -1); 236 | 237 | memset(&vid_format, 0, sizeof(vid_format)); 238 | 239 | ret_code = ioctl(fdwr, VIDIOC_G_FMT, &vid_format); 240 | if(debug)print_format(&vid_format); 241 | 242 | vid_format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; 243 | vid_format.fmt.pix.width = FRAME_WIDTH; 244 | vid_format.fmt.pix.height = FRAME_HEIGHT; 245 | vid_format.fmt.pix.pixelformat = FRAME_FORMAT; 246 | vid_format.fmt.pix.sizeimage = framesize; 247 | vid_format.fmt.pix.field = V4L2_FIELD_NONE; 248 | vid_format.fmt.pix.bytesperline = linewidth; 249 | vid_format.fmt.pix.colorspace = V4L2_COLORSPACE_SRGB; 250 | 251 | if(debug)print_format(&vid_format); 252 | ret_code = ioctl(fdwr, VIDIOC_S_FMT, &vid_format); 253 | 254 | assert(ret_code != -1); 255 | 256 | if(debug)printf("frame: format=%d\tsize=%d\n", FRAME_FORMAT, framesize); 257 | print_format(&vid_format); 258 | 259 | if(!format_properties(vid_format.fmt.pix.pixelformat, 260 | vid_format.fmt.pix.width, vid_format.fmt.pix.height, 261 | &linewidth, 262 | &framesize)) { 263 | printf("unable to guess correct settings for format '%d'\n", FRAME_FORMAT); 264 | } 265 | buffer=(__u8*)malloc(sizeof(__u8)*framesize); 266 | check_buffer=(__u8*)malloc(sizeof(__u8)*framesize); 267 | 268 | memset(buffer, 0, framesize); 269 | memset(check_buffer, 0, framesize); 270 | for (i = 0; i < framesize; ++i) { 271 | //buffer[i] = i % 2; 272 | check_buffer[i] = 0; 273 | } 274 | 275 | 276 | 277 | 278 | 279 | //write(fdwr, buffer, framesize); 280 | writeYV12(fdwr, buffer, framesize, 15); 281 | 282 | #ifdef CHECK_REREAD 283 | do { 284 | /* check if we get the same data on output */ 285 | int fdr = open(video_device, O_RDONLY); 286 | read(fdr, check_buffer, framesize); 287 | for (i = 0; i < framesize; ++i) { 288 | if (buffer[i] != check_buffer[i]) 289 | assert(0); 290 | } 291 | close(fdr); 292 | } while(0); 293 | #endif 294 | 295 | pause(); 296 | 297 | close(fdwr); 298 | 299 | free(buffer); 300 | free(check_buffer); 301 | 302 | return 0; 303 | } 304 | -------------------------------------------------------------------------------- /v4l2loopback.c: -------------------------------------------------------------------------------- 1 | /* 2 | * v4l2loopback.c -- video4linux2 loopback driver 3 | * 4 | * Copyright (C) 2005-2009 Vasily Levin (vasaka@gmail.com) 5 | * Copyright (C) 2010-2012 IOhannes m zmoelnig (zmoelnig@iem.at) 6 | * Copyright (C) 2011 Stefan Diewald (stefan.diewald@mytum.de) 7 | * Copyright (C) 2012 Anton Novikov (random.plant@gmail.com) 8 | * 9 | * This program is free software; you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation; either version 2 of the License, or 12 | * (at your option) any later version. 13 | * 14 | */ 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29) 23 | # include 24 | #else 25 | /* dummy v4l2_device struct/functions */ 26 | # define V4L2_DEVICE_NAME_SIZE (20 + 16) 27 | struct v4l2_device { 28 | char name[V4L2_DEVICE_NAME_SIZE]; 29 | }; 30 | static inline int v4l2_device_register (void *dev, void *v4l2_dev) { return 0; } 31 | static inline void v4l2_device_unregister(struct v4l2_device *v4l2_dev) { return; } 32 | #endif 33 | #include 34 | #include 35 | 36 | #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29) 37 | # define v4l2_file_operations file_operations 38 | #endif 39 | #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 37) 40 | void *v4l2l_vzalloc(unsigned long size) 41 | { 42 | void *data = vmalloc(size); 43 | 44 | memset(data, 0, size); 45 | return data; 46 | } 47 | #else 48 | # define v4l2l_vzalloc vzalloc 49 | #endif 50 | 51 | 52 | #include 53 | #include 54 | 55 | #define V4L2LOOPBACK_VERSION_CODE KERNEL_VERSION(0, 8, 0) 56 | 57 | 58 | MODULE_DESCRIPTION("V4L2 loopback video device"); 59 | MODULE_AUTHOR("Vasily Levin, " \ 60 | "IOhannes m zmoelnig ," \ 61 | "Stefan Diewald," \ 62 | "Anton Novikov" \ 63 | ); 64 | MODULE_LICENSE("GPL"); 65 | 66 | 67 | /* helpers */ 68 | #define STRINGIFY(s) #s 69 | #define STRINGIFY2(s) STRINGIFY(s) 70 | 71 | #define dprintk(fmt, args...) \ 72 | do { if (debug > 0) { \ 73 | printk(KERN_INFO "v4l2-loopback[" STRINGIFY2(__LINE__) "]: " fmt, ##args); \ 74 | } } while (0) 75 | 76 | #define MARK() \ 77 | do { if (debug > 1) { \ 78 | printk(KERN_INFO "%s:%d[%s]\n", __FILE__, __LINE__, __func__); \ 79 | } } while (0) 80 | 81 | #define dprintkrw(fmt, args...) \ 82 | do { if (debug > 2) { \ 83 | printk(KERN_INFO "v4l2-loopback[" STRINGIFY2(__LINE__)"]: " fmt, ##args); \ 84 | } } while (0) 85 | 86 | 87 | /* module constants 88 | * can be overridden during he build process using something like 89 | * make KCPPFLAGS="-DMAX_DEVICES=100" 90 | */ 91 | 92 | 93 | /* maximum number of v4l2loopback devices that can be created */ 94 | #ifndef MAX_DEVICES 95 | # define MAX_DEVICES 8 96 | #endif 97 | 98 | /* when a producer is considered to have gone stale */ 99 | #ifndef MAX_TIMEOUT 100 | # define MAX_TIMEOUT (100 * 1000 * 1000) /* in msecs */ 101 | #endif 102 | 103 | /* max buffers that can be mapped, actually they 104 | * are all mapped to max_buffers buffers */ 105 | #ifndef MAX_BUFFERS 106 | # define MAX_BUFFERS 32 107 | #endif 108 | 109 | /* module parameters */ 110 | static int debug; 111 | module_param(debug, int, S_IRUGO | S_IWUSR); 112 | MODULE_PARM_DESC(debug, "debugging level (higher values == more verbose)"); 113 | 114 | static int max_buffers = 8; 115 | module_param(max_buffers, int, S_IRUGO); 116 | MODULE_PARM_DESC(max_buffers, "how many buffers should be allocated"); 117 | 118 | /* how many times a device can be opened 119 | * the per-module default value can be overridden on a per-device basis using 120 | * the /sys/devices interface 121 | * 122 | * note that max_openers should be at least 2 in order to get a working system: 123 | * one opener for the producer and one opener for the consumer 124 | * however, we leave that to the user 125 | */ 126 | static int max_openers = 10; 127 | module_param(max_openers, int, S_IRUGO | S_IWUSR); 128 | MODULE_PARM_DESC(max_openers, "how many users can open loopback device"); 129 | 130 | 131 | static int devices = -1; 132 | module_param(devices, int, 0); 133 | MODULE_PARM_DESC(devices, "how many devices should be created"); 134 | 135 | 136 | static int video_nr[MAX_DEVICES] = { [0 ... (MAX_DEVICES - 1)] = -1 }; 137 | module_param_array(video_nr, int, NULL, 0444); 138 | MODULE_PARM_DESC(video_nr, "video device numbers (-1=auto, 0=/dev/video0, etc.)"); 139 | 140 | static char *card_label[MAX_DEVICES]; 141 | module_param_array(card_label, charp, NULL, 0000); 142 | MODULE_PARM_DESC(card_label, "card labels for every device"); 143 | 144 | static bool exclusive_caps[MAX_DEVICES] = { [0 ... (MAX_DEVICES - 1)] = 1 }; 145 | module_param_array(exclusive_caps, bool, NULL, 0444); 146 | /* FIXXME: wording */ 147 | MODULE_PARM_DESC(exclusive_caps, "whether to announce OUTPUT/CAPTURE capabilities exclusively or not"); 148 | 149 | 150 | /* format specifications */ 151 | #define V4L2LOOPBACK_SIZE_MIN_WIDTH 48 152 | #define V4L2LOOPBACK_SIZE_MIN_HEIGHT 32 153 | #define V4L2LOOPBACK_SIZE_MAX_WIDTH 8192 154 | #define V4L2LOOPBACK_SIZE_MAX_HEIGHT 8192 155 | 156 | #define V4L2LOOPBACK_SIZE_DEFAULT_WIDTH 640 157 | #define V4L2LOOPBACK_SIZE_DEFAULT_HEIGHT 480 158 | 159 | static int max_width = V4L2LOOPBACK_SIZE_MAX_WIDTH; 160 | module_param(max_width, int, S_IRUGO); 161 | MODULE_PARM_DESC(max_width, "maximum frame width"); 162 | static int max_height = V4L2LOOPBACK_SIZE_MAX_HEIGHT; 163 | module_param(max_height, int, S_IRUGO); 164 | MODULE_PARM_DESC(max_height, "maximum frame height"); 165 | 166 | 167 | /* control IDs */ 168 | #define CID_KEEP_FORMAT (V4L2_CID_PRIVATE_BASE + 0) 169 | #define CID_SUSTAIN_FRAMERATE (V4L2_CID_PRIVATE_BASE + 1) 170 | #define CID_TIMEOUT (V4L2_CID_PRIVATE_BASE + 2) 171 | #define CID_TIMEOUT_IMAGE_IO (V4L2_CID_PRIVATE_BASE + 3) 172 | 173 | 174 | /* module structures */ 175 | struct v4l2loopback_private { 176 | int devicenr; 177 | }; 178 | 179 | /* TODO(vasaka) use typenames which are common to kernel, but first find out if 180 | * it is needed */ 181 | /* struct keeping state and settings of loopback device */ 182 | 183 | struct v4l2l_buffer { 184 | struct v4l2_buffer buffer; 185 | struct list_head list_head; 186 | int use_count; 187 | }; 188 | 189 | struct v4l2_loopback_device { 190 | struct v4l2_device v4l2_dev; 191 | struct video_device *vdev; 192 | /* pixel and stream format */ 193 | struct v4l2_pix_format pix_format; 194 | struct v4l2_captureparm capture_param; 195 | unsigned long frame_jiffies; 196 | 197 | /* ctrls */ 198 | int keep_format; /* CID_KEEP_FORMAT; stay ready_for_capture even when all 199 | openers close() the device */ 200 | int sustain_framerate; /* CID_SUSTAIN_FRAMERATE; duplicate frames to maintain 201 | (close to) nominal framerate */ 202 | 203 | /* buffers stuff */ 204 | u8 *image; /* pointer to actual buffers data */ 205 | unsigned long int imagesize; /* size of buffers data */ 206 | int buffers_number; /* should not be big, 4 is a good choice */ 207 | struct v4l2l_buffer buffers[MAX_BUFFERS]; /* inner driver buffers */ 208 | int used_buffers; /* number of the actually used buffers */ 209 | int max_openers; /* how many times can this device be opened */ 210 | 211 | int write_position; /* number of last written frame + 1 */ 212 | struct list_head outbufs_list; /* buffers in output DQBUF order */ 213 | int bufpos2index[MAX_BUFFERS]; /* mapping of (read/write_position % used_buffers) 214 | * to inner buffer index */ 215 | long buffer_size; 216 | 217 | /* sustain_framerate stuff */ 218 | struct timer_list sustain_timer; 219 | unsigned int reread_count; 220 | 221 | /* timeout stuff */ 222 | unsigned long timeout_jiffies; /* CID_TIMEOUT; 0 means disabled */ 223 | int timeout_image_io; /* CID_TIMEOUT_IMAGE_IO; next opener will 224 | * read/write to timeout_image */ 225 | u8 *timeout_image; /* copy of it will be captured when timeout passes */ 226 | struct v4l2l_buffer timeout_image_buffer; 227 | struct timer_list timeout_timer; 228 | int timeout_happened; 229 | 230 | /* sync stuff */ 231 | atomic_t open_count; 232 | 233 | 234 | int ready_for_capture;/* set to true when at least one writer opened 235 | * device and negotiated format */ 236 | int ready_for_output; /* set to true when no writer is currently attached 237 | * this differs slightly from !ready_for_capture, 238 | * e.g. when using fallback images */ 239 | int announce_all_caps;/* set to false, if device caps (OUTPUT/CAPTURE) 240 | * should only be announced if the resp. "ready" 241 | * flag is set; default=TRUE */ 242 | 243 | wait_queue_head_t read_event; 244 | spinlock_t lock; 245 | }; 246 | 247 | /* types of opener shows what opener wants to do with loopback */ 248 | enum opener_type { 249 | UNNEGOTIATED = 0, 250 | READER = 1, 251 | WRITER = 2, 252 | }; 253 | 254 | /* struct keeping state and type of opener */ 255 | struct v4l2_loopback_opener { 256 | enum opener_type type; 257 | int vidioc_enum_frameintervals_calls; 258 | int read_position; /* number of last processed frame + 1 or 259 | * write_position - 1 if reader went out of sync */ 260 | unsigned int reread_count; 261 | struct v4l2_buffer *buffers; 262 | int buffers_number; /* should not be big, 4 is a good choice */ 263 | int timeout_image_io; 264 | }; 265 | 266 | /* this is heavily inspired by the bttv driver found in the linux kernel */ 267 | struct v4l2l_format { 268 | char *name; 269 | int fourcc; /* video4linux 2 */ 270 | int depth; /* bit/pixel */ 271 | int flags; 272 | }; 273 | /* set the v4l2l_format.flags to PLANAR for non-packed formats */ 274 | #define FORMAT_FLAGS_PLANAR 0x01 275 | 276 | static const struct v4l2l_format formats[] = { 277 | /* here come the packed formats */ 278 | { 279 | .name = "32 bpp RGB, le", 280 | .fourcc = V4L2_PIX_FMT_BGR32, 281 | .depth = 32, 282 | .flags = 0, 283 | }, { 284 | .name = "32 bpp RGB, be", 285 | .fourcc = V4L2_PIX_FMT_RGB32, 286 | .depth = 32, 287 | .flags = 0, 288 | }, { 289 | .name = "24 bpp RGB, le", 290 | .fourcc = V4L2_PIX_FMT_BGR24, 291 | .depth = 24, 292 | .flags = 0, 293 | }, { 294 | .name = "24 bpp RGB, be", 295 | .fourcc = V4L2_PIX_FMT_RGB24, 296 | .depth = 24, 297 | .flags = 0, 298 | }, { 299 | .name = "4:2:2, packed, YUYV", 300 | .fourcc = V4L2_PIX_FMT_YUYV, 301 | .depth = 16, 302 | .flags = 0, 303 | }, { 304 | .name = "4:2:2, packed, YUYV", 305 | .fourcc = V4L2_PIX_FMT_YUYV, 306 | .depth = 16, 307 | .flags = 0, 308 | }, { 309 | .name = "4:2:2, packed, UYVY", 310 | .fourcc = V4L2_PIX_FMT_UYVY, 311 | .depth = 16, 312 | .flags = 0, 313 | }, { 314 | #ifdef V4L2_PIX_FMT_YVYU 315 | .name = "4:2:2, packed YVYU", 316 | .fourcc = V4L2_PIX_FMT_YVYU, 317 | .depth = 16, 318 | .flags = 0, 319 | }, { 320 | #endif 321 | #ifdef V4L2_PIX_FMT_VYUY 322 | .name = "4:2:2, packed VYUY", 323 | .fourcc = V4L2_PIX_FMT_VYUY, 324 | .depth = 16, 325 | .flags = 0, 326 | }, { 327 | #endif 328 | .name = "4:2:2, packed YYUV", 329 | .fourcc = V4L2_PIX_FMT_YYUV, 330 | .depth = 16, 331 | .flags = 0, 332 | }, { 333 | .name = "YUV-8-8-8-8", 334 | .fourcc = V4L2_PIX_FMT_YUV32, 335 | .depth = 32, 336 | .flags = 0, 337 | }, { 338 | .name = "8 bpp, gray", 339 | .fourcc = V4L2_PIX_FMT_GREY, 340 | .depth = 8, 341 | .flags = 0, 342 | }, { 343 | .name = "16 Greyscale", 344 | .fourcc = V4L2_PIX_FMT_Y16, 345 | .depth = 16, 346 | .flags = 0, 347 | }, 348 | 349 | /* here come the planar formats */ 350 | { 351 | .name = "4:1:0, planar, Y-Cr-Cb", 352 | .fourcc = V4L2_PIX_FMT_YVU410, 353 | .depth = 9, 354 | .flags = FORMAT_FLAGS_PLANAR, 355 | }, { 356 | .name = "4:2:0, planar, Y-Cr-Cb", 357 | .fourcc = V4L2_PIX_FMT_YVU420, 358 | .depth = 12, 359 | .flags = FORMAT_FLAGS_PLANAR, 360 | }, { 361 | .name = "4:1:0, planar, Y-Cb-Cr", 362 | .fourcc = V4L2_PIX_FMT_YUV410, 363 | .depth = 9, 364 | .flags = FORMAT_FLAGS_PLANAR, 365 | }, { 366 | .name = "4:2:0, planar, Y-Cb-Cr", 367 | .fourcc = V4L2_PIX_FMT_YUV420, 368 | .depth = 12, 369 | .flags = FORMAT_FLAGS_PLANAR, 370 | } 371 | }; 372 | 373 | static const unsigned int FORMATS = ARRAY_SIZE(formats); 374 | 375 | 376 | static char *fourcc2str(unsigned int fourcc, char buf[4]) 377 | { 378 | buf[0] = (fourcc >> 0) & 0xFF; 379 | buf[1] = (fourcc >> 8) & 0xFF; 380 | buf[2] = (fourcc >> 16) & 0xFF; 381 | buf[3] = (fourcc >> 24) & 0xFF; 382 | 383 | return buf; 384 | } 385 | 386 | static const struct v4l2l_format *format_by_fourcc(int fourcc) 387 | { 388 | unsigned int i; 389 | 390 | for (i = 0; i < FORMATS; i++) { 391 | if (formats[i].fourcc == fourcc) 392 | return formats + i; 393 | } 394 | 395 | dprintk("unsupported format '%c%c%c%c'\n", 396 | (fourcc >> 0) & 0xFF, 397 | (fourcc >> 8) & 0xFF, 398 | (fourcc >> 16) & 0xFF, 399 | (fourcc >> 24) & 0xFF); 400 | return NULL; 401 | } 402 | 403 | static void pix_format_set_size(struct v4l2_pix_format *f, 404 | const struct v4l2l_format *fmt, 405 | unsigned int width, unsigned int height) 406 | { 407 | f->width = width; 408 | f->height = height; 409 | 410 | if (fmt->flags & FORMAT_FLAGS_PLANAR) { 411 | f->bytesperline = width; /* Y plane */ 412 | f->sizeimage = (width * height * fmt->depth) >> 3; 413 | } else { 414 | f->bytesperline = (width * fmt->depth) >> 3; 415 | f->sizeimage = height * f->bytesperline; 416 | } 417 | } 418 | 419 | static void set_timeperframe(struct v4l2_loopback_device *dev, 420 | struct v4l2_fract *tpf) 421 | { 422 | dev->capture_param.timeperframe = *tpf; 423 | dev->frame_jiffies = max(1UL, 424 | msecs_to_jiffies(1000) * tpf->numerator / tpf->denominator); 425 | } 426 | 427 | static struct v4l2_loopback_device *v4l2loopback_cd2dev(struct device *cd); 428 | 429 | /* device attributes */ 430 | /* available via sysfs: /sys/devices/virtual/video4linux/video* */ 431 | 432 | static ssize_t attr_show_format(struct device *cd, 433 | struct device_attribute *attr, char *buf) 434 | { 435 | /* gets the current format as "FOURCC:WxH@f/s", e.g. "YUYV:320x240@1000/30" */ 436 | struct v4l2_loopback_device *dev = v4l2loopback_cd2dev(cd); 437 | const struct v4l2_fract *tpf; 438 | char buf4cc[5], buf_fps[32]; 439 | 440 | if (!dev || !dev->ready_for_capture) 441 | return 0; 442 | tpf = &dev->capture_param.timeperframe; 443 | 444 | fourcc2str(dev->pix_format.pixelformat, buf4cc); 445 | if (tpf->numerator == 1) 446 | snprintf(buf_fps, sizeof(buf_fps), "%d", tpf->denominator); 447 | else 448 | snprintf(buf_fps, sizeof(buf_fps), "%d/%d", 449 | tpf->denominator, tpf->numerator); 450 | 451 | return sprintf(buf, "%4s:%dx%d@%s\n", 452 | buf4cc, dev->pix_format.width, dev->pix_format.height, buf_fps); 453 | } 454 | 455 | static ssize_t attr_store_format(struct device *cd, 456 | struct device_attribute *attr, const char *buf, size_t len) 457 | { 458 | struct v4l2_loopback_device *dev = v4l2loopback_cd2dev(cd); 459 | int fps_num = 0, fps_den = 1; 460 | 461 | /* only fps changing is supported */ 462 | if (sscanf(buf, "@%d/%d", &fps_num, &fps_den) > 0) { 463 | struct v4l2_fract f = { 464 | .numerator = fps_den, 465 | .denominator = fps_num 466 | }; 467 | 468 | if (fps_num < 1 || fps_den < 1) 469 | return -EINVAL; 470 | set_timeperframe(dev, &f); 471 | return len; 472 | } 473 | return -EINVAL; 474 | } 475 | 476 | static DEVICE_ATTR(format, S_IRUGO | S_IWUSR, attr_show_format, attr_store_format); 477 | 478 | static ssize_t attr_show_buffers(struct device *cd, 479 | struct device_attribute *attr, char *buf) 480 | { 481 | struct v4l2_loopback_device *dev = v4l2loopback_cd2dev(cd); 482 | 483 | return sprintf(buf, "%d\n", dev->used_buffers); 484 | } 485 | 486 | static DEVICE_ATTR(buffers, S_IRUGO, attr_show_buffers, NULL); 487 | 488 | static ssize_t attr_show_maxopeners(struct device *cd, 489 | struct device_attribute *attr, char *buf) 490 | { 491 | struct v4l2_loopback_device *dev = v4l2loopback_cd2dev(cd); 492 | 493 | return sprintf(buf, "%d\n", dev->max_openers); 494 | } 495 | 496 | static ssize_t attr_store_maxopeners(struct device *cd, 497 | struct device_attribute *attr, const char *buf, size_t len) 498 | { 499 | struct v4l2_loopback_device *dev = NULL; 500 | unsigned long curr = 0; 501 | 502 | if (strict_strtoul(buf, 0, &curr)) 503 | return -EINVAL; 504 | 505 | dev = v4l2loopback_cd2dev(cd); 506 | 507 | if (dev->max_openers == curr) 508 | return len; 509 | 510 | if (dev->open_count.counter > curr) { 511 | /* request to limit to less openers as are currently attached to us */ 512 | return -EINVAL; 513 | } 514 | 515 | dev->max_openers = (int)curr; 516 | 517 | return len; 518 | } 519 | 520 | 521 | static DEVICE_ATTR(max_openers, S_IRUGO | S_IWUSR, attr_show_maxopeners, attr_store_maxopeners); 522 | 523 | static void v4l2loopback_remove_sysfs(struct video_device *vdev) 524 | { 525 | #define V4L2_SYSFS_DESTROY(x) device_remove_file(&vdev->dev, &dev_attr_##x) 526 | 527 | if (vdev) { 528 | V4L2_SYSFS_DESTROY(format); 529 | V4L2_SYSFS_DESTROY(buffers); 530 | V4L2_SYSFS_DESTROY(max_openers); 531 | /* ... */ 532 | } 533 | } 534 | 535 | static void v4l2loopback_create_sysfs(struct video_device *vdev) 536 | { 537 | int res = 0; 538 | 539 | #define V4L2_SYSFS_CREATE(x) res = device_create_file(&vdev->dev, &dev_attr_##x); if (res < 0) break 540 | if (!vdev) 541 | return; 542 | do { 543 | V4L2_SYSFS_CREATE(format); 544 | V4L2_SYSFS_CREATE(buffers); 545 | V4L2_SYSFS_CREATE(max_openers); 546 | /* ... */ 547 | } while (0); 548 | 549 | if (res >= 0) 550 | return; 551 | dev_err(&vdev->dev, "%s error: %d\n", __func__, res); 552 | } 553 | 554 | /* global module data */ 555 | struct v4l2_loopback_device *devs[MAX_DEVICES]; 556 | 557 | static struct v4l2_loopback_device *v4l2loopback_cd2dev(struct device *cd) 558 | { 559 | struct video_device *loopdev = to_video_device(cd); 560 | struct v4l2loopback_private *ptr = 561 | (struct v4l2loopback_private *)video_get_drvdata(loopdev); 562 | int nr = ptr->devicenr; 563 | 564 | if (nr < 0 || nr >= devices) { 565 | printk(KERN_ERR "v4l2-loopback: illegal device %d\n", nr); 566 | return NULL; 567 | } 568 | return devs[nr]; 569 | } 570 | 571 | static struct v4l2_loopback_device *v4l2loopback_getdevice(struct file *f) 572 | { 573 | struct video_device *loopdev = video_devdata(f); 574 | struct v4l2loopback_private *ptr = 575 | (struct v4l2loopback_private *)video_get_drvdata(loopdev); 576 | int nr = ptr->devicenr; 577 | 578 | if (nr < 0 || nr >= devices) { 579 | printk(KERN_ERR "v4l2-loopback: illegal device %d\n", nr); 580 | return NULL; 581 | } 582 | return devs[nr]; 583 | } 584 | 585 | /* forward declarations */ 586 | static void init_buffers(struct v4l2_loopback_device *dev); 587 | static int allocate_buffers(struct v4l2_loopback_device *dev); 588 | static int free_buffers(struct v4l2_loopback_device *dev); 589 | static void try_free_buffers(struct v4l2_loopback_device *dev); 590 | static int allocate_timeout_image(struct v4l2_loopback_device *dev); 591 | static void check_timers(struct v4l2_loopback_device *dev); 592 | static const struct v4l2_file_operations v4l2_loopback_fops; 593 | static const struct v4l2_ioctl_ops v4l2_loopback_ioctl_ops; 594 | 595 | /* Queue helpers */ 596 | /* next functions sets buffer flags and adjusts counters accordingly */ 597 | static inline void set_done(struct v4l2l_buffer *buffer) 598 | { 599 | buffer->buffer.flags &= ~V4L2_BUF_FLAG_QUEUED; 600 | buffer->buffer.flags |= V4L2_BUF_FLAG_DONE; 601 | } 602 | 603 | static inline void set_queued(struct v4l2l_buffer *buffer) 604 | { 605 | buffer->buffer.flags &= ~V4L2_BUF_FLAG_DONE; 606 | buffer->buffer.flags |= V4L2_BUF_FLAG_QUEUED; 607 | } 608 | 609 | static inline void unset_flags(struct v4l2l_buffer *buffer) 610 | { 611 | buffer->buffer.flags &= ~V4L2_BUF_FLAG_QUEUED; 612 | buffer->buffer.flags &= ~V4L2_BUF_FLAG_DONE; 613 | } 614 | 615 | /* V4L2 ioctl caps and params calls */ 616 | /* returns device capabilities 617 | * called on VIDIOC_QUERYCAP 618 | */ 619 | static int vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *cap) 620 | { 621 | struct v4l2_loopback_device *dev = v4l2loopback_getdevice(file); 622 | int devnr = ((struct v4l2loopback_private *)video_get_drvdata(dev->vdev))->devicenr; 623 | 624 | strlcpy(cap->driver, "v4l2 loopback", sizeof(cap->driver)); 625 | 626 | if (card_label[devnr] != NULL) { 627 | snprintf(cap->card, sizeof(cap->card), card_label[devnr]); 628 | } else { 629 | snprintf(cap->card, sizeof(cap->card), "Dummy video device (0x%04X)", devnr); 630 | } 631 | 632 | snprintf(cap->bus_info, sizeof(cap->bus_info), "v4l2loopback:%d", devnr); 633 | 634 | cap->version = V4L2LOOPBACK_VERSION_CODE; 635 | cap->capabilities = 636 | V4L2_CAP_STREAMING | V4L2_CAP_READWRITE; 637 | if (dev->announce_all_caps) { 638 | cap->capabilities |= V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT; 639 | } else { 640 | 641 | if (dev->ready_for_capture) { 642 | cap->capabilities |= V4L2_CAP_VIDEO_CAPTURE; 643 | } 644 | if (dev->ready_for_output) { 645 | cap->capabilities |= V4L2_CAP_VIDEO_OUTPUT; 646 | } 647 | } 648 | 649 | memset(cap->reserved, 0, sizeof(cap->reserved)); 650 | return 0; 651 | } 652 | 653 | static int vidioc_enum_framesizes(struct file *file, void *fh, struct v4l2_frmsizeenum *argp) 654 | { 655 | struct v4l2_loopback_device *dev; 656 | 657 | /* LATER: what does the index really mean? 658 | * if it's about enumerating formats, we can safely ignore it 659 | * (CHECK) 660 | */ 661 | 662 | /* there can be only one... */ 663 | if (argp->index) 664 | return -EINVAL; 665 | 666 | dev = v4l2loopback_getdevice(file); 667 | if (dev->ready_for_capture) { 668 | /* format has already been negotiated 669 | * cannot change during runtime 670 | */ 671 | argp->type = V4L2_FRMSIZE_TYPE_DISCRETE; 672 | 673 | argp->discrete.width = dev->pix_format.width; 674 | argp->discrete.height = dev->pix_format.height; 675 | } else { 676 | /* if the format has not been negotiated yet, we accept anything 677 | */ 678 | argp->type = V4L2_FRMSIZE_TYPE_CONTINUOUS; 679 | 680 | argp->stepwise.min_width = V4L2LOOPBACK_SIZE_MIN_WIDTH; 681 | argp->stepwise.min_height = V4L2LOOPBACK_SIZE_MIN_HEIGHT; 682 | 683 | argp->stepwise.max_width = max_width; 684 | argp->stepwise.max_height = max_height; 685 | 686 | argp->stepwise.step_width = 1; 687 | argp->stepwise.step_height = 1; 688 | } 689 | return 0; 690 | } 691 | 692 | /* returns frameinterval (fps) for the set resolution 693 | * called on VIDIOC_ENUM_FRAMEINTERVALS 694 | */ 695 | static int vidioc_enum_frameintervals(struct file *file, void *fh, struct v4l2_frmivalenum *argp) 696 | { 697 | struct v4l2_loopback_device *dev = v4l2loopback_getdevice(file); 698 | struct v4l2_loopback_opener *opener = file->private_data; 699 | 700 | if (dev->ready_for_capture) { 701 | if (opener->vidioc_enum_frameintervals_calls > 0) 702 | return -EINVAL; 703 | if (argp->width == dev->pix_format.width && 704 | argp->height == dev->pix_format.height) { 705 | argp->type = V4L2_FRMIVAL_TYPE_DISCRETE; 706 | argp->discrete = dev->capture_param.timeperframe; 707 | opener->vidioc_enum_frameintervals_calls++; 708 | return 0; 709 | } 710 | return -EINVAL; 711 | } 712 | return 0; 713 | } 714 | 715 | /* ------------------ CAPTURE ----------------------- */ 716 | 717 | /* returns device formats 718 | * called on VIDIOC_ENUM_FMT, with v4l2_buf_type set to V4L2_BUF_TYPE_VIDEO_CAPTURE 719 | */ 720 | static int vidioc_enum_fmt_cap(struct file *file, void *fh, struct v4l2_fmtdesc *f) 721 | { 722 | struct v4l2_loopback_device *dev; 723 | MARK(); 724 | 725 | dev = v4l2loopback_getdevice(file); 726 | 727 | if (f->index) 728 | return -EINVAL; 729 | if (dev->ready_for_capture) { 730 | const __u32 format = dev->pix_format.pixelformat; 731 | 732 | snprintf(f->description, sizeof(f->description), 733 | "[%c%c%c%c]", 734 | (format >> 0) & 0xFF, 735 | (format >> 8) & 0xFF, 736 | (format >> 16) & 0xFF, 737 | (format >> 24) & 0xFF); 738 | 739 | f->pixelformat = dev->pix_format.pixelformat; 740 | } else { 741 | return -EINVAL; 742 | } 743 | f->flags = 0; 744 | MARK(); 745 | return 0; 746 | } 747 | 748 | /* returns current video format format fmt 749 | * called on VIDIOC_G_FMT, with v4l2_buf_type set to V4L2_BUF_TYPE_VIDEO_CAPTURE 750 | */ 751 | static int vidioc_g_fmt_cap(struct file *file, void *priv, struct v4l2_format *fmt) 752 | { 753 | struct v4l2_loopback_device *dev; 754 | MARK(); 755 | 756 | dev = v4l2loopback_getdevice(file); 757 | 758 | if (!dev->ready_for_capture) 759 | return -EINVAL; 760 | 761 | fmt->fmt.pix = dev->pix_format; 762 | MARK(); 763 | return 0; 764 | } 765 | 766 | /* checks if it is OK to change to format fmt; 767 | * actual check is done by inner_try_fmt_cap 768 | * just checking that pixelformat is OK and set other parameters, app should 769 | * obey this decision 770 | * called on VIDIOC_TRY_FMT, with v4l2_buf_type set to V4L2_BUF_TYPE_VIDEO_CAPTURE 771 | */ 772 | static int vidioc_try_fmt_cap(struct file *file, void *priv, struct v4l2_format *fmt) 773 | { 774 | struct v4l2_loopback_opener *opener; 775 | struct v4l2_loopback_device *dev; 776 | char buf[5]; 777 | 778 | opener = file->private_data; 779 | opener->type = READER; 780 | 781 | dev = v4l2loopback_getdevice(file); 782 | 783 | if (0 == dev->ready_for_capture) { 784 | dprintk("setting fmt_cap not possible yet\n"); 785 | return -EBUSY; 786 | } 787 | 788 | if (fmt->fmt.pix.pixelformat != dev->pix_format.pixelformat) 789 | return -EINVAL; 790 | 791 | fmt->fmt.pix = dev->pix_format; 792 | 793 | buf[4] = 0; 794 | dprintk("capFOURCC=%s\n", fourcc2str(dev->pix_format.pixelformat, buf)); 795 | return 0; 796 | } 797 | 798 | /* sets new output format, if possible 799 | * actually format is set by input and we even do not check it, just return 800 | * current one, but it is possible to set subregions of input TODO(vasaka) 801 | * called on VIDIOC_S_FMT, with v4l2_buf_type set to V4L2_BUF_TYPE_VIDEO_CAPTURE 802 | */ 803 | static int vidioc_s_fmt_cap(struct file *file, void *priv, struct v4l2_format *fmt) 804 | { 805 | return vidioc_try_fmt_cap(file, priv, fmt); 806 | } 807 | 808 | 809 | /* ------------------ OUTPUT ----------------------- */ 810 | 811 | /* returns device formats; 812 | * LATER: allow all formats 813 | * called on VIDIOC_ENUM_FMT, with v4l2_buf_type set to V4L2_BUF_TYPE_VIDEO_OUTPUT 814 | */ 815 | static int vidioc_enum_fmt_out(struct file *file, void *fh, struct v4l2_fmtdesc *f) 816 | { 817 | struct v4l2_loopback_device *dev; 818 | const struct v4l2l_format *fmt; 819 | 820 | dev = v4l2loopback_getdevice(file); 821 | 822 | if (dev->ready_for_capture) { 823 | const __u32 format = dev->pix_format.pixelformat; 824 | 825 | /* format has been fixed by the writer, so only one single format is supported */ 826 | if (f->index) 827 | return -EINVAL; 828 | 829 | fmt = format_by_fourcc(format); 830 | if (NULL == fmt) 831 | return -EINVAL; 832 | 833 | f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 834 | /* f->flags = ??; */ 835 | snprintf(f->description, sizeof(f->description), "%s", fmt->name); 836 | 837 | f->pixelformat = dev->pix_format.pixelformat; 838 | } else { 839 | __u32 format; 840 | /* fill in a dummy format */ 841 | if (f->index < 0 || f->index >= FORMATS) 842 | return -EINVAL; 843 | 844 | fmt = &formats[f->index]; 845 | 846 | f->pixelformat = fmt->fourcc; 847 | format = f->pixelformat; 848 | 849 | /* strlcpy(f->description, "dummy OUT format", sizeof(f->description)); */ 850 | snprintf(f->description, sizeof(f->description), "%s", fmt->name); 851 | 852 | } 853 | f->flags = 0; 854 | 855 | return 0; 856 | } 857 | 858 | /* returns current video format format fmt */ 859 | /* NOTE: this is called from the producer 860 | * so if format has not been negotiated yet, 861 | * it should return ALL of available formats, 862 | * called on VIDIOC_G_FMT, with v4l2_buf_type set to V4L2_BUF_TYPE_VIDEO_OUTPUT 863 | */ 864 | static int vidioc_g_fmt_out(struct file *file, void *priv, struct v4l2_format *fmt) 865 | { 866 | struct v4l2_loopback_device *dev; 867 | struct v4l2_loopback_opener *opener; 868 | 869 | MARK(); 870 | 871 | dev = v4l2loopback_getdevice(file); 872 | opener = file->private_data; 873 | opener->type = WRITER; 874 | dev->ready_for_output = 1; 875 | /* 876 | * LATER: this should return the currently valid format 877 | * gstreamer doesn't like it, if this returns -EINVAL, as it 878 | * then concludes that there is _no_ valid format 879 | * CHECK whether this assumption is wrong, 880 | * or whether we have to always provide a valid format 881 | */ 882 | 883 | fmt->fmt.pix = dev->pix_format; 884 | return 0; 885 | } 886 | 887 | /* checks if it is OK to change to format fmt; 888 | * if format is negotiated do not change it 889 | * called on VIDIOC_TRY_FMT with v4l2_buf_type set to V4L2_BUF_TYPE_VIDEO_OUTPUT 890 | */ 891 | static int vidioc_try_fmt_out(struct file *file, void *priv, struct v4l2_format *fmt) 892 | { 893 | struct v4l2_loopback_opener *opener; 894 | struct v4l2_loopback_device *dev; 895 | MARK(); 896 | 897 | opener = file->private_data; 898 | opener->type = WRITER; 899 | 900 | dev = v4l2loopback_getdevice(file); 901 | dev->ready_for_output = 1; 902 | 903 | /* TODO(vasaka) loopback does not care about formats writer want to set, 904 | * maybe it is a good idea to restrict format somehow */ 905 | if (dev->ready_for_capture) { 906 | fmt->fmt.pix = dev->pix_format; 907 | } else { 908 | __u32 w = fmt->fmt.pix.width; 909 | __u32 h = fmt->fmt.pix.height; 910 | __u32 pixfmt = fmt->fmt.pix.pixelformat; 911 | const struct v4l2l_format *format = format_by_fourcc(pixfmt); 912 | 913 | if (w > max_width) 914 | w = max_width; 915 | if (h > max_height) 916 | h = max_height; 917 | 918 | dprintk("trying image %dx%d\n", w, h); 919 | 920 | if (w < 1) 921 | w = V4L2LOOPBACK_SIZE_DEFAULT_WIDTH; 922 | 923 | if (h < 1) 924 | h = V4L2LOOPBACK_SIZE_DEFAULT_HEIGHT; 925 | 926 | if (NULL == format) 927 | format = &formats[0]; 928 | 929 | pix_format_set_size(&fmt->fmt.pix, format, w, h); 930 | 931 | fmt->fmt.pix.pixelformat = format->fourcc; 932 | fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB; 933 | 934 | if (V4L2_FIELD_ANY == fmt->fmt.pix.field) 935 | fmt->fmt.pix.field = V4L2_FIELD_NONE; 936 | 937 | /* FIXXME: try_fmt should never modify the device-state */ 938 | dev->pix_format = fmt->fmt.pix; 939 | } 940 | return 0; 941 | } 942 | 943 | /* sets new output format, if possible; 944 | * allocate data here because we do not know if it will be streaming or 945 | * read/write IO 946 | * called on VIDIOC_S_FMT with v4l2_buf_type set to V4L2_BUF_TYPE_VIDEO_OUTPUT 947 | */ 948 | static int vidioc_s_fmt_out(struct file *file, void *priv, struct v4l2_format *fmt) 949 | { 950 | struct v4l2_loopback_device *dev; 951 | char buf[5]; 952 | int ret; 953 | MARK(); 954 | 955 | dev = v4l2loopback_getdevice(file); 956 | ret = vidioc_try_fmt_out(file, priv, fmt); 957 | 958 | dprintk("s_fmt_out(%d) %d...%d\n", ret, dev->ready_for_capture, dev->pix_format.sizeimage); 959 | 960 | buf[4] = 0; 961 | dprintk("outFOURCC=%s\n", fourcc2str(dev->pix_format.pixelformat, buf)); 962 | 963 | if (ret < 0) 964 | return ret; 965 | 966 | if (!dev->ready_for_capture) { 967 | dev->buffer_size = PAGE_ALIGN(dev->pix_format.sizeimage); 968 | fmt->fmt.pix.sizeimage = dev->buffer_size; 969 | allocate_buffers(dev); 970 | } 971 | return ret; 972 | } 973 | 974 | /*#define V4L2L_OVERLAY*/ 975 | #ifdef V4L2L_OVERLAY 976 | /* ------------------ OVERLAY ----------------------- */ 977 | /* currently unsupported */ 978 | /* GSTreamer's v4l2sink is buggy, as it requires the overlay to work 979 | * while it should only require it, if overlay is requested 980 | * once the gstreamer element is fixed, remove the overlay dummies 981 | */ 982 | #warning OVERLAY dummies 983 | static int vidioc_g_fmt_overlay(struct file *file, void *priv, struct v4l2_format *fmt) 984 | { 985 | return 0; 986 | } 987 | 988 | static int vidioc_s_fmt_overlay(struct file *file, void *priv, struct v4l2_format *fmt) 989 | { 990 | return 0; 991 | } 992 | #endif /* V4L2L_OVERLAY */ 993 | 994 | 995 | /* ------------------ PARAMs ----------------------- */ 996 | 997 | /* get some data flow parameters, only capability, fps and readbuffers has 998 | * effect on this driver 999 | * called on VIDIOC_G_PARM 1000 | */ 1001 | static int vidioc_g_parm(struct file *file, void *priv, struct v4l2_streamparm *parm) 1002 | { 1003 | /* do not care about type of opener, hope this enums would always be 1004 | * compatible */ 1005 | struct v4l2_loopback_device *dev; 1006 | MARK(); 1007 | 1008 | dev = v4l2loopback_getdevice(file); 1009 | parm->parm.capture = dev->capture_param; 1010 | return 0; 1011 | } 1012 | 1013 | /* get some data flow parameters, only capability, fps and readbuffers has 1014 | * effect on this driver 1015 | * called on VIDIOC_S_PARM 1016 | */ 1017 | static int vidioc_s_parm(struct file *file, void *priv, struct v4l2_streamparm *parm) 1018 | { 1019 | struct v4l2_loopback_device *dev; 1020 | MARK(); 1021 | 1022 | dev = v4l2loopback_getdevice(file); 1023 | dprintk("vidioc_s_parm called frate=%d/%d\n", 1024 | parm->parm.capture.timeperframe.numerator, 1025 | parm->parm.capture.timeperframe.denominator); 1026 | 1027 | switch (parm->type) { 1028 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: 1029 | set_timeperframe(dev, &parm->parm.capture.timeperframe); 1030 | break; 1031 | case V4L2_BUF_TYPE_VIDEO_OUTPUT: 1032 | set_timeperframe(dev, &parm->parm.capture.timeperframe); 1033 | break; 1034 | default: 1035 | return -1; 1036 | } 1037 | 1038 | parm->parm.capture = dev->capture_param; 1039 | return 0; 1040 | } 1041 | 1042 | #ifdef V4L2LOOPBACK_WITH_STD 1043 | /* sets a tv standard, actually we do not need to handle this any special way 1044 | * added to support effecttv 1045 | * called on VIDIOC_S_STD 1046 | */ 1047 | static int vidioc_s_std(struct file *file, void *private_data, v4l2_std_id *_std) 1048 | { 1049 | v4l2_std_id req_std = 0, supported_std = 0; 1050 | const v4l2_std_id all_std = V4L2_STD_ALL, no_std = 0; 1051 | 1052 | if (_std) { 1053 | req_std = *_std; 1054 | *_std = all_std; 1055 | } 1056 | 1057 | /* we support everything in V4L2_STD_ALL, but not more... */ 1058 | supported_std = (all_std & req_std); 1059 | if (no_std == supported_std) 1060 | return -EINVAL; 1061 | 1062 | return 0; 1063 | } 1064 | 1065 | 1066 | /* gets a fake video standard 1067 | * called on VIDIOC_G_STD 1068 | */ 1069 | static int vidioc_g_std(struct file *file, void *private_data, v4l2_std_id *norm) 1070 | { 1071 | if (norm) 1072 | *norm = V4L2_STD_ALL; 1073 | return 0; 1074 | } 1075 | /* gets a fake video standard 1076 | * called on VIDIOC_QUERYSTD 1077 | */ 1078 | static int vidioc_querystd(struct file *file, void *private_data, v4l2_std_id *norm) 1079 | { 1080 | if (norm) 1081 | *norm = V4L2_STD_ALL; 1082 | return 0; 1083 | } 1084 | #endif /* V4L2LOOPBACK_WITH_STD */ 1085 | 1086 | /* get ctrls info 1087 | * called on VIDIOC_QUERYCTRL 1088 | */ 1089 | static int vidioc_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *q) 1090 | { 1091 | switch (q->id) { 1092 | case CID_KEEP_FORMAT: 1093 | case CID_SUSTAIN_FRAMERATE: 1094 | case CID_TIMEOUT_IMAGE_IO: 1095 | q->type = V4L2_CTRL_TYPE_BOOLEAN; 1096 | q->minimum = 0; 1097 | q->maximum = 1; 1098 | q->step = 1; 1099 | break; 1100 | case CID_TIMEOUT: 1101 | q->type = V4L2_CTRL_TYPE_INTEGER; 1102 | q->minimum = 0; 1103 | q->maximum = MAX_TIMEOUT; 1104 | q->step = 1; 1105 | break; 1106 | default: 1107 | return -EINVAL; 1108 | } 1109 | 1110 | switch (q->id) { 1111 | case CID_KEEP_FORMAT: 1112 | strcpy(q->name, "keep_format"); 1113 | q->default_value = 0; 1114 | break; 1115 | case CID_SUSTAIN_FRAMERATE: 1116 | strcpy(q->name, "sustain_framerate"); 1117 | q->default_value = 0; 1118 | break; 1119 | case CID_TIMEOUT: 1120 | strcpy(q->name, "timeout"); 1121 | q->default_value = 0; 1122 | break; 1123 | case CID_TIMEOUT_IMAGE_IO: 1124 | strcpy(q->name, "timeout_image_io"); 1125 | q->default_value = 0; 1126 | break; 1127 | default: 1128 | BUG(); 1129 | } 1130 | 1131 | memset(q->reserved, 0, sizeof(q->reserved)); 1132 | return 0; 1133 | } 1134 | 1135 | 1136 | static int vidioc_g_ctrl(struct file *file, void *fh, struct v4l2_control *c) 1137 | { 1138 | struct v4l2_loopback_device *dev = v4l2loopback_getdevice(file); 1139 | 1140 | switch (c->id) { 1141 | case CID_KEEP_FORMAT: 1142 | c->value = dev->keep_format; 1143 | break; 1144 | case CID_SUSTAIN_FRAMERATE: 1145 | c->value = dev->sustain_framerate; 1146 | break; 1147 | case CID_TIMEOUT: 1148 | c->value = jiffies_to_msecs(dev->timeout_jiffies); 1149 | break; 1150 | case CID_TIMEOUT_IMAGE_IO: 1151 | c->value = dev->timeout_image_io; 1152 | break; 1153 | default: 1154 | return -EINVAL; 1155 | } 1156 | 1157 | return 0; 1158 | } 1159 | 1160 | 1161 | static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *c) 1162 | { 1163 | struct v4l2_loopback_device *dev = v4l2loopback_getdevice(file); 1164 | 1165 | switch (c->id) { 1166 | case CID_KEEP_FORMAT: 1167 | if (c->value < 0 || c->value > 1) 1168 | return -EINVAL; 1169 | dev->keep_format = c->value; 1170 | try_free_buffers(dev); 1171 | break; 1172 | case CID_SUSTAIN_FRAMERATE: 1173 | if (c->value < 0 || c->value > 1) 1174 | return -EINVAL; 1175 | spin_lock_bh(&dev->lock); 1176 | dev->sustain_framerate = c->value; 1177 | check_timers(dev); 1178 | spin_unlock_bh(&dev->lock); 1179 | break; 1180 | case CID_TIMEOUT: 1181 | if (c->value < 0 || c->value > MAX_TIMEOUT) 1182 | return -EINVAL; 1183 | spin_lock_bh(&dev->lock); 1184 | dev->timeout_jiffies = msecs_to_jiffies(c->value); 1185 | check_timers(dev); 1186 | spin_unlock_bh(&dev->lock); 1187 | allocate_timeout_image(dev); 1188 | break; 1189 | case CID_TIMEOUT_IMAGE_IO: 1190 | if (c->value < 0 || c->value > 1) 1191 | return -EINVAL; 1192 | dev->timeout_image_io = c->value; 1193 | break; 1194 | default: 1195 | return -EINVAL; 1196 | } 1197 | 1198 | return 0; 1199 | } 1200 | 1201 | 1202 | /* returns set of device outputs, in our case there is only one 1203 | * called on VIDIOC_ENUMOUTPUT 1204 | */ 1205 | static int vidioc_enum_output(struct file *file, void *fh, struct v4l2_output *outp) 1206 | { 1207 | __u32 index = outp->index; 1208 | MARK(); 1209 | 1210 | if (0 != index) 1211 | return -EINVAL; 1212 | 1213 | /* clear all data (including the reserved fields) */ 1214 | memset(outp, 0, sizeof(*outp)); 1215 | 1216 | outp->index = index; 1217 | strlcpy(outp->name, "loopback in", sizeof(outp->name)); 1218 | outp->type = V4L2_OUTPUT_TYPE_ANALOG; 1219 | outp->audioset = 0; 1220 | outp->modulator = 0; 1221 | #ifdef V4L2LOOPBACK_WITH_STD 1222 | outp->std = V4L2_STD_ALL; 1223 | # ifdef V4L2_OUT_CAP_STD 1224 | outp->capabilities |= V4L2_OUT_CAP_STD; 1225 | # endif /* V4L2_OUT_CAP_STD */ 1226 | #endif /* V4L2LOOPBACK_WITH_STD */ 1227 | 1228 | return 0; 1229 | } 1230 | 1231 | /* which output is currently active, 1232 | * called on VIDIOC_G_OUTPUT 1233 | */ 1234 | static int vidioc_g_output(struct file *file, void *fh, unsigned int *i) 1235 | { 1236 | if (i) 1237 | *i = 0; 1238 | return 0; 1239 | } 1240 | 1241 | /* set output, can make sense if we have more than one video src, 1242 | * called on VIDIOC_S_OUTPUT 1243 | */ 1244 | static int vidioc_s_output(struct file *file, void *fh, unsigned int i) 1245 | { 1246 | if (i) 1247 | return -EINVAL; 1248 | i = 0; 1249 | 1250 | if (v4l2loopback_getdevice(file)->ready_for_capture) 1251 | return -EBUSY; 1252 | 1253 | return 0; 1254 | } 1255 | 1256 | 1257 | /* returns set of device inputs, in our case there is only one, 1258 | * but later I may add more 1259 | * called on VIDIOC_ENUMINPUT 1260 | */ 1261 | static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *inp) 1262 | { 1263 | __u32 index = inp->index; 1264 | MARK(); 1265 | 1266 | if (0 != index) 1267 | return -EINVAL; 1268 | 1269 | if (!v4l2loopback_getdevice(file)->ready_for_capture) 1270 | return -EINVAL; 1271 | 1272 | /* clear all data (including the reserved fields) */ 1273 | memset(inp, 0, sizeof(*inp)); 1274 | 1275 | inp->index = index; 1276 | strlcpy(inp->name, "loopback", sizeof(inp->name)); 1277 | inp->type = V4L2_INPUT_TYPE_CAMERA; 1278 | inp->audioset = 0; 1279 | inp->tuner = 0; 1280 | inp->status = 0; 1281 | 1282 | #ifdef V4L2LOOPBACK_WITH_STD 1283 | inp->std = V4L2_STD_ALL; 1284 | # ifdef V4L2_IN_CAP_STD 1285 | inp->capabilities |= V4L2_IN_CAP_STD; 1286 | # endif 1287 | #endif /* V4L2LOOPBACK_WITH_STD */ 1288 | 1289 | return 0; 1290 | } 1291 | 1292 | /* which input is currently active, 1293 | * called on VIDIOC_G_INPUT 1294 | */ 1295 | static int vidioc_g_input(struct file *file, void *fh, unsigned int *i) 1296 | { 1297 | if (!v4l2loopback_getdevice(file)->ready_for_capture) 1298 | return -EINVAL; 1299 | if (i) 1300 | *i = 0; 1301 | return 0; 1302 | } 1303 | 1304 | /* set input, can make sense if we have more than one video src, 1305 | * called on VIDIOC_S_INPUT 1306 | */ 1307 | static int vidioc_s_input(struct file *file, void *fh, unsigned int i) 1308 | { 1309 | if ((i == 0) && (v4l2loopback_getdevice(file)->ready_for_capture)) 1310 | return 0; 1311 | 1312 | return -EINVAL; 1313 | } 1314 | 1315 | /* --------------- V4L2 ioctl buffer related calls ----------------- */ 1316 | 1317 | /* negotiate buffer type 1318 | * only mmap streaming supported 1319 | * called on VIDIOC_REQBUFS 1320 | */ 1321 | static int vidioc_reqbufs(struct file *file, void *fh, struct v4l2_requestbuffers *b) 1322 | { 1323 | struct v4l2_loopback_device *dev; 1324 | struct v4l2_loopback_opener *opener; 1325 | int i; 1326 | MARK(); 1327 | 1328 | dev = v4l2loopback_getdevice(file); 1329 | opener = file->private_data; 1330 | 1331 | dprintk("reqbufs: %d\t%d=%d\n", b->memory, b->count, dev->buffers_number); 1332 | if (opener->timeout_image_io) { 1333 | if (b->memory != V4L2_MEMORY_MMAP) 1334 | return -EINVAL; 1335 | b->count = 1; 1336 | return 0; 1337 | } 1338 | 1339 | init_buffers(dev); 1340 | switch (b->memory) { 1341 | case V4L2_MEMORY_MMAP: 1342 | /* do nothing here, buffers are always allocated*/ 1343 | if (0 == b->count) 1344 | return 0; 1345 | 1346 | if (b->count > dev->buffers_number) 1347 | b->count = dev->buffers_number; 1348 | 1349 | /* make sure that outbufs_list contains buffers from 0 to used_buffers-1 1350 | * actually, it will have been already populated via v4l2_loopback_init() 1351 | * at this point */ 1352 | if (list_empty(&dev->outbufs_list)) { 1353 | for (i = 0; i < dev->used_buffers; ++i) 1354 | list_add_tail(&dev->buffers[i].list_head, &dev->outbufs_list); 1355 | } 1356 | 1357 | /* also, if dev->used_buffers is going to be decreased, we should remove 1358 | * out-of-range buffers from outbufs_list, and fix bufpos2index mapping */ 1359 | if (b->count < dev->used_buffers) { 1360 | struct v4l2l_buffer *pos, *n; 1361 | 1362 | list_for_each_entry_safe(pos, n, &dev->outbufs_list, list_head) { 1363 | if (pos->buffer.index >= b->count) 1364 | list_del(&pos->list_head); 1365 | } 1366 | 1367 | /* after we update dev->used_buffers, buffers in outbufs_list will 1368 | * correspond to dev->write_position + [0;b->count-1] range */ 1369 | i = dev->write_position; 1370 | list_for_each_entry(pos, &dev->outbufs_list, list_head) { 1371 | dev->bufpos2index[i % b->count] = pos->buffer.index; 1372 | ++i; 1373 | } 1374 | } 1375 | 1376 | opener->buffers_number = b->count; 1377 | if (opener->buffers_number < dev->used_buffers) 1378 | dev->used_buffers = opener->buffers_number; 1379 | return 0; 1380 | default: 1381 | return -EINVAL; 1382 | } 1383 | } 1384 | 1385 | /* returns buffer asked for; 1386 | * give app as many buffers as it wants, if it less than MAX, 1387 | * but map them in our inner buffers 1388 | * called on VIDIOC_QUERYBUF 1389 | */ 1390 | static int vidioc_querybuf(struct file *file, void *fh, struct v4l2_buffer *b) 1391 | { 1392 | enum v4l2_buf_type type; 1393 | int index; 1394 | struct v4l2_loopback_device *dev; 1395 | struct v4l2_loopback_opener *opener; 1396 | 1397 | MARK(); 1398 | 1399 | type = b->type; 1400 | index = b->index; 1401 | dev = v4l2loopback_getdevice(file); 1402 | opener = file->private_data; 1403 | 1404 | if ((b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) && 1405 | (b->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)) { 1406 | return -EINVAL; 1407 | } 1408 | if (b->index > max_buffers) 1409 | return -EINVAL; 1410 | 1411 | if (opener->timeout_image_io) 1412 | *b = dev->timeout_image_buffer.buffer; 1413 | else 1414 | *b = dev->buffers[b->index % dev->used_buffers].buffer; 1415 | 1416 | b->type = type; 1417 | b->index = index; 1418 | dprintkrw("buffer type: %d (of %d with size=%ld)\n", b->memory, dev->buffers_number, dev->buffer_size); 1419 | return 0; 1420 | } 1421 | 1422 | static void buffer_written(struct v4l2_loopback_device *dev, struct v4l2l_buffer *buf) 1423 | { 1424 | del_timer_sync(&dev->sustain_timer); 1425 | del_timer_sync(&dev->timeout_timer); 1426 | spin_lock_bh(&dev->lock); 1427 | 1428 | dev->bufpos2index[dev->write_position % dev->used_buffers] = buf->buffer.index; 1429 | list_move_tail(&buf->list_head, &dev->outbufs_list); 1430 | ++dev->write_position; 1431 | dev->reread_count = 0; 1432 | 1433 | check_timers(dev); 1434 | spin_unlock_bh(&dev->lock); 1435 | } 1436 | 1437 | /* put buffer to queue 1438 | * called on VIDIOC_QBUF 1439 | */ 1440 | static int vidioc_qbuf(struct file *file, void *private_data, struct v4l2_buffer *buf) 1441 | { 1442 | struct v4l2_loopback_device *dev; 1443 | struct v4l2_loopback_opener *opener; 1444 | struct v4l2l_buffer *b; 1445 | int index; 1446 | 1447 | dev = v4l2loopback_getdevice(file); 1448 | opener = file->private_data; 1449 | 1450 | if (buf->index > max_buffers) 1451 | return -EINVAL; 1452 | if (opener->timeout_image_io) 1453 | return 0; 1454 | 1455 | index = buf->index % dev->used_buffers; 1456 | b = &dev->buffers[index]; 1457 | 1458 | switch (buf->type) { 1459 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: 1460 | dprintkrw("capture QBUF index: %d\n", index); 1461 | set_queued(b); 1462 | return 0; 1463 | case V4L2_BUF_TYPE_VIDEO_OUTPUT: 1464 | dprintkrw("output QBUF pos: %d index: %d\n", dev->write_position, index); 1465 | do_gettimeofday(&b->buffer.timestamp); 1466 | set_done(b); 1467 | buffer_written(dev, b); 1468 | wake_up_all(&dev->read_event); 1469 | return 0; 1470 | default: 1471 | return -EINVAL; 1472 | } 1473 | } 1474 | 1475 | static int can_read(struct v4l2_loopback_device *dev, struct v4l2_loopback_opener *opener) 1476 | { 1477 | int ret; 1478 | 1479 | spin_lock_bh(&dev->lock); 1480 | check_timers(dev); 1481 | ret = dev->write_position > opener->read_position 1482 | || dev->reread_count > opener->reread_count 1483 | || dev->timeout_happened; 1484 | spin_unlock_bh(&dev->lock); 1485 | return ret; 1486 | } 1487 | 1488 | static int get_capture_buffer(struct file *file) 1489 | { 1490 | struct v4l2_loopback_device *dev = v4l2loopback_getdevice(file); 1491 | struct v4l2_loopback_opener *opener = file->private_data; 1492 | int pos, ret; 1493 | int timeout_happened; 1494 | 1495 | if ((file->f_flags & O_NONBLOCK) && 1496 | (dev->write_position <= opener->read_position && 1497 | dev->reread_count <= opener->reread_count && !dev->timeout_happened)) 1498 | return -EAGAIN; 1499 | wait_event_interruptible(dev->read_event, can_read(dev, opener)); 1500 | 1501 | spin_lock_bh(&dev->lock); 1502 | if (dev->write_position == opener->read_position) { 1503 | if (dev->reread_count > opener->reread_count + 2) 1504 | opener->reread_count = dev->reread_count - 1; 1505 | ++opener->reread_count; 1506 | pos = (opener->read_position + dev->used_buffers - 1) % dev->used_buffers; 1507 | } else { 1508 | opener->reread_count = 0; 1509 | if (dev->write_position > opener->read_position + 2) 1510 | opener->read_position = dev->write_position - 1; 1511 | pos = opener->read_position % dev->used_buffers; 1512 | ++opener->read_position; 1513 | } 1514 | timeout_happened = dev->timeout_happened; 1515 | dev->timeout_happened = 0; 1516 | spin_unlock_bh(&dev->lock); 1517 | 1518 | ret = dev->bufpos2index[pos]; 1519 | if (timeout_happened) { 1520 | /* although allocated on-demand, timeout_image is freed only 1521 | * in free_buffers(), so we don't need to worry about it being 1522 | * deallocated suddenly */ 1523 | memcpy(dev->image + dev->buffers[ret].buffer.m.offset, 1524 | dev->timeout_image, dev->buffer_size); 1525 | } 1526 | return ret; 1527 | } 1528 | 1529 | /* put buffer to dequeue 1530 | * called on VIDIOC_DQBUF 1531 | */ 1532 | static int vidioc_dqbuf(struct file *file, void *private_data, struct v4l2_buffer *buf) 1533 | { 1534 | struct v4l2_loopback_device *dev; 1535 | struct v4l2_loopback_opener *opener; 1536 | int index; 1537 | struct v4l2l_buffer *b; 1538 | 1539 | dev = v4l2loopback_getdevice(file); 1540 | opener = file->private_data; 1541 | if (opener->timeout_image_io) { 1542 | *buf = dev->timeout_image_buffer.buffer; 1543 | return 0; 1544 | } 1545 | 1546 | switch (buf->type) { 1547 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: 1548 | index = get_capture_buffer(file); 1549 | if (index < 0) 1550 | return index; 1551 | dprintkrw("capture DQBUF pos: %d index: %d\n", opener->read_position - 1, index); 1552 | if (!(dev->buffers[index].buffer.flags&V4L2_BUF_FLAG_MAPPED)) { 1553 | dprintk("trying to return not mapped buf[%d]\n", index); 1554 | return -EINVAL; 1555 | } 1556 | unset_flags(&dev->buffers[index]); 1557 | *buf = dev->buffers[index].buffer; 1558 | return 0; 1559 | case V4L2_BUF_TYPE_VIDEO_OUTPUT: 1560 | b = list_entry(dev->outbufs_list.next, struct v4l2l_buffer, list_head); 1561 | list_move_tail(&b->list_head, &dev->outbufs_list); 1562 | dprintkrw("output DQBUF index: %d\n", b->buffer.index); 1563 | unset_flags(b); 1564 | *buf = b->buffer; 1565 | buf->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; 1566 | return 0; 1567 | default: 1568 | return -EINVAL; 1569 | } 1570 | } 1571 | 1572 | /* ------------- STREAMING ------------------- */ 1573 | 1574 | /* start streaming 1575 | * called on VIDIOC_STREAMON 1576 | */ 1577 | static int vidioc_streamon(struct file *file, void *private_data, enum v4l2_buf_type type) 1578 | { 1579 | struct v4l2_loopback_device *dev; 1580 | int ret; 1581 | MARK(); 1582 | 1583 | dev = v4l2loopback_getdevice(file); 1584 | 1585 | switch (type) { 1586 | case V4L2_BUF_TYPE_VIDEO_OUTPUT: 1587 | dev->ready_for_output = 0; 1588 | if (!dev->ready_for_capture) { 1589 | ret = allocate_buffers(dev); 1590 | if (ret < 0) 1591 | return ret; 1592 | dev->ready_for_capture = 1; 1593 | } 1594 | return 0; 1595 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: 1596 | if (!dev->ready_for_capture) 1597 | return -EIO; 1598 | return 0; 1599 | default: 1600 | return -EINVAL; 1601 | } 1602 | } 1603 | 1604 | /* stop streaming 1605 | * called on VIDIOC_STREAMOFF 1606 | */ 1607 | static int vidioc_streamoff(struct file *file, void *private_data, enum v4l2_buf_type type) 1608 | { 1609 | MARK(); 1610 | dprintk("%d\n", type); 1611 | return 0; 1612 | } 1613 | 1614 | #ifdef CONFIG_VIDEO_V4L1_COMPAT 1615 | static int vidiocgmbuf(struct file *file, void *fh, struct video_mbuf *p) 1616 | { 1617 | struct v4l2_loopback_device *dev; 1618 | MARK(); 1619 | 1620 | dev = v4l2loopback_getdevice(file); 1621 | p->frames = dev->buffers_number; 1622 | p->offsets[0] = 0; 1623 | p->offsets[1] = 0; 1624 | p->size = dev->buffer_size; 1625 | return 0; 1626 | } 1627 | #endif 1628 | 1629 | /* file operations */ 1630 | static void vm_open(struct vm_area_struct *vma) 1631 | { 1632 | struct v4l2l_buffer *buf; 1633 | MARK(); 1634 | 1635 | buf = vma->vm_private_data; 1636 | buf->use_count++; 1637 | } 1638 | 1639 | static void vm_close(struct vm_area_struct *vma) 1640 | { 1641 | struct v4l2l_buffer *buf; 1642 | MARK(); 1643 | 1644 | buf = vma->vm_private_data; 1645 | buf->use_count--; 1646 | } 1647 | 1648 | static struct vm_operations_struct vm_ops = { 1649 | .open = vm_open, 1650 | .close = vm_close, 1651 | }; 1652 | 1653 | static int v4l2_loopback_mmap(struct file *file, struct vm_area_struct *vma) 1654 | { 1655 | int i; 1656 | unsigned long addr; 1657 | unsigned long start; 1658 | unsigned long size; 1659 | struct v4l2_loopback_device *dev; 1660 | struct v4l2_loopback_opener *opener; 1661 | struct v4l2l_buffer *buffer = NULL; 1662 | MARK(); 1663 | 1664 | start = (unsigned long) vma->vm_start; 1665 | size = (unsigned long) (vma->vm_end - vma->vm_start); 1666 | 1667 | dev = v4l2loopback_getdevice(file); 1668 | opener = file->private_data; 1669 | 1670 | if (size > dev->buffer_size) { 1671 | dprintk("userspace tries to mmap too much, fail\n"); 1672 | return -EINVAL; 1673 | } 1674 | if (opener->timeout_image_io) { 1675 | /* we are going to map the timeout_image_buffer */ 1676 | if ((vma->vm_pgoff << PAGE_SHIFT) != dev->buffer_size * MAX_BUFFERS) { 1677 | dprintk("invalid mmap offset for timeout_image_io mode\n"); 1678 | return -EINVAL; 1679 | } 1680 | } else if ((vma->vm_pgoff << PAGE_SHIFT) > 1681 | dev->buffer_size * (dev->buffers_number - 1)) { 1682 | dprintk("userspace tries to mmap too far, fail\n"); 1683 | return -EINVAL; 1684 | } 1685 | 1686 | /* FIXXXXXME: allocation should not happen here! */ 1687 | if (NULL == dev->image) 1688 | if (allocate_buffers(dev) < 0) 1689 | return -EINVAL; 1690 | 1691 | if (opener->timeout_image_io) { 1692 | buffer = &dev->timeout_image_buffer; 1693 | addr = (unsigned long)dev->timeout_image; 1694 | } else { 1695 | for (i = 0; i < dev->buffers_number; ++i) { 1696 | buffer = &dev->buffers[i]; 1697 | if ((buffer->buffer.m.offset >> PAGE_SHIFT) == vma->vm_pgoff) 1698 | break; 1699 | } 1700 | 1701 | if (NULL == buffer) 1702 | return -EINVAL; 1703 | 1704 | addr = (unsigned long) dev->image + (vma->vm_pgoff << PAGE_SHIFT); 1705 | } 1706 | 1707 | while (size > 0) { 1708 | struct page *page; 1709 | 1710 | page = (void *)vmalloc_to_page((void *)addr); 1711 | 1712 | if (vm_insert_page(vma, start, page) < 0) 1713 | return -EAGAIN; 1714 | 1715 | start += PAGE_SIZE; 1716 | addr += PAGE_SIZE; 1717 | size -= PAGE_SIZE; 1718 | } 1719 | 1720 | vma->vm_ops = &vm_ops; 1721 | vma->vm_private_data = buffer; 1722 | buffer->buffer.flags |= V4L2_BUF_FLAG_MAPPED; 1723 | 1724 | vm_open(vma); 1725 | 1726 | MARK(); 1727 | return 0; 1728 | } 1729 | 1730 | static unsigned int v4l2_loopback_poll(struct file *file, struct poll_table_struct *pts) 1731 | { 1732 | struct v4l2_loopback_opener *opener; 1733 | struct v4l2_loopback_device *dev; 1734 | int ret_mask = 0; 1735 | MARK(); 1736 | 1737 | opener = file->private_data; 1738 | dev = v4l2loopback_getdevice(file); 1739 | 1740 | switch (opener->type) { 1741 | case WRITER: 1742 | ret_mask = POLLOUT | POLLWRNORM; 1743 | break; 1744 | case READER: 1745 | poll_wait(file, &dev->read_event, pts); 1746 | if (can_read(dev, opener)) 1747 | ret_mask = POLLIN | POLLRDNORM; 1748 | break; 1749 | default: 1750 | ret_mask = -POLLERR; 1751 | } 1752 | MARK(); 1753 | 1754 | return ret_mask; 1755 | } 1756 | 1757 | /* do not want to limit device opens, it can be as many readers as user want, 1758 | * writers are limited by means of setting writer field */ 1759 | static int v4l2_loopback_open(struct file *file) 1760 | { 1761 | struct v4l2_loopback_device *dev; 1762 | struct v4l2_loopback_opener *opener; 1763 | MARK(); 1764 | 1765 | dev = v4l2loopback_getdevice(file); 1766 | 1767 | if (dev->open_count.counter >= dev->max_openers) 1768 | return -EBUSY; 1769 | /* kfree on close */ 1770 | opener = kzalloc(sizeof(*opener), GFP_KERNEL); 1771 | if (opener == NULL) 1772 | return -ENOMEM; 1773 | file->private_data = opener; 1774 | atomic_inc(&dev->open_count); 1775 | 1776 | opener->timeout_image_io = dev->timeout_image_io; 1777 | dev->timeout_image_io = 0; 1778 | 1779 | if (opener->timeout_image_io) { 1780 | int r = allocate_timeout_image(dev); 1781 | 1782 | if (r < 0) { 1783 | dprintk("timeout image allocation failed\n"); 1784 | return r; 1785 | } 1786 | } 1787 | dprintk("opened dev:%p with image:%p\n", dev, dev ? dev->image : NULL); 1788 | MARK(); 1789 | return 0; 1790 | } 1791 | 1792 | static int v4l2_loopback_close(struct file *file) 1793 | { 1794 | struct v4l2_loopback_opener *opener; 1795 | struct v4l2_loopback_device *dev; 1796 | int iswriter=0; 1797 | MARK(); 1798 | 1799 | opener = file->private_data; 1800 | dev = v4l2loopback_getdevice(file); 1801 | 1802 | if(WRITER == opener->type) 1803 | iswriter = 1; 1804 | 1805 | atomic_dec(&dev->open_count); 1806 | if (dev->open_count.counter == 0) { 1807 | del_timer_sync(&dev->sustain_timer); 1808 | del_timer_sync(&dev->timeout_timer); 1809 | } 1810 | try_free_buffers(dev); 1811 | kfree(opener); 1812 | if(iswriter) { 1813 | dev->ready_for_output = 1; 1814 | } 1815 | MARK(); 1816 | return 0; 1817 | } 1818 | 1819 | static ssize_t v4l2_loopback_read(struct file *file, 1820 | char __user *buf, size_t count, loff_t *ppos) 1821 | { 1822 | int read_index; 1823 | struct v4l2_loopback_opener *opener; 1824 | struct v4l2_loopback_device *dev; 1825 | MARK(); 1826 | 1827 | opener = file->private_data; 1828 | dev = v4l2loopback_getdevice(file); 1829 | 1830 | read_index = get_capture_buffer(file); 1831 | if (count > dev->buffer_size) 1832 | count = dev->buffer_size; 1833 | if (copy_to_user((void *)buf, (void *)(dev->image + 1834 | dev->buffers[read_index].buffer.m.offset), count)) { 1835 | printk(KERN_ERR 1836 | "v4l2-loopback: failed copy_from_user() in write buf\n"); 1837 | return -EFAULT; 1838 | } 1839 | dprintkrw("leave v4l2_loopback_read()\n"); 1840 | return count; 1841 | } 1842 | 1843 | static ssize_t v4l2_loopback_write(struct file *file, 1844 | const char __user *buf, size_t count, loff_t *ppos) 1845 | { 1846 | struct v4l2_loopback_device *dev; 1847 | int write_index; 1848 | struct v4l2_buffer *b; 1849 | int ret; 1850 | MARK(); 1851 | 1852 | dev = v4l2loopback_getdevice(file); 1853 | 1854 | /* there's at least one writer, so don'stop announcing output capabilities */ 1855 | dev->ready_for_output = 0; 1856 | 1857 | if (!dev->ready_for_capture) { 1858 | ret = allocate_buffers(dev); 1859 | if (ret < 0) 1860 | return ret; 1861 | dev->ready_for_capture = 1; 1862 | } 1863 | dprintkrw("v4l2_loopback_write() trying to write %zu bytes\n", count); 1864 | if (count > dev->buffer_size) 1865 | count = dev->buffer_size; 1866 | 1867 | write_index = dev->write_position % dev->used_buffers; 1868 | b = &dev->buffers[write_index].buffer; 1869 | 1870 | if (copy_from_user((void *)(dev->image + b->m.offset), (void *)buf, count)) { 1871 | printk(KERN_ERR 1872 | "v4l2-loopback: failed copy_from_user() in write buf, could not write %zu\n", 1873 | count); 1874 | return -EFAULT; 1875 | } 1876 | do_gettimeofday(&b->timestamp); 1877 | b->sequence = dev->write_position; 1878 | buffer_written(dev, &dev->buffers[write_index]); 1879 | wake_up_all(&dev->read_event); 1880 | dprintkrw("leave v4l2_loopback_write()\n"); 1881 | return count; 1882 | } 1883 | 1884 | /* init functions */ 1885 | /* frees buffers, if already allocated */ 1886 | static int free_buffers(struct v4l2_loopback_device *dev) 1887 | { 1888 | MARK(); 1889 | dprintk("freeing image@%p for dev:%p\n", dev ? dev->image : NULL, dev); 1890 | if (dev->image) { 1891 | vfree(dev->image); 1892 | dev->image = NULL; 1893 | } 1894 | if (dev->timeout_image) { 1895 | vfree(dev->timeout_image); 1896 | dev->timeout_image = NULL; 1897 | } 1898 | dev->imagesize = 0; 1899 | 1900 | return 0; 1901 | } 1902 | /* frees buffers, if they are no longer needed */ 1903 | static void try_free_buffers(struct v4l2_loopback_device *dev) 1904 | { 1905 | MARK(); 1906 | if (0 == dev->open_count.counter && !dev->keep_format) { 1907 | free_buffers(dev); 1908 | dev->ready_for_capture = 0; 1909 | dev->buffer_size = 0; 1910 | dev->write_position = 0; 1911 | } 1912 | } 1913 | /* allocates buffers, if buffer_size is set */ 1914 | static int allocate_buffers(struct v4l2_loopback_device *dev) 1915 | { 1916 | MARK(); 1917 | /* vfree on close file operation in case no open handles left */ 1918 | if (0 == dev->buffer_size) 1919 | return -EINVAL; 1920 | 1921 | if (dev->image) { 1922 | dprintk("allocating buffers again: %ld %ld\n", 1923 | dev->buffer_size * dev->buffers_number, dev->imagesize); 1924 | /* FIXME: prevent double allocation more intelligently! */ 1925 | if (dev->buffer_size * dev->buffers_number == dev->imagesize) 1926 | return 0; 1927 | 1928 | /* if there is only one writer, no problem should occur */ 1929 | if (dev->open_count.counter == 1) 1930 | free_buffers(dev); 1931 | else 1932 | return -EINVAL; 1933 | } 1934 | 1935 | dev->imagesize = dev->buffer_size * dev->buffers_number; 1936 | 1937 | dprintk("allocating %ld = %ldx%d\n", dev->imagesize, dev->buffer_size, dev->buffers_number); 1938 | 1939 | dev->image = vmalloc(dev->imagesize); 1940 | if (dev->timeout_jiffies > 0) 1941 | allocate_timeout_image(dev); 1942 | 1943 | if (dev->image == NULL) 1944 | return -ENOMEM; 1945 | dprintk("vmallocated %ld bytes\n", dev->imagesize); 1946 | MARK(); 1947 | init_buffers(dev); 1948 | return 0; 1949 | } 1950 | 1951 | /* init inner buffers, they are capture mode and flags are set as 1952 | * for capture mod buffers */ 1953 | static void init_buffers(struct v4l2_loopback_device *dev) 1954 | { 1955 | int i; 1956 | int buffer_size; 1957 | int bytesused; 1958 | MARK(); 1959 | 1960 | buffer_size = dev->buffer_size; 1961 | bytesused = dev->pix_format.sizeimage; 1962 | 1963 | for (i = 0; i < dev->buffers_number; ++i) { 1964 | struct v4l2_buffer *b = &dev->buffers[i].buffer; 1965 | b->index = i; 1966 | b->bytesused = bytesused; 1967 | b->length = buffer_size; 1968 | b->field = V4L2_FIELD_NONE; 1969 | b->flags = 0; 1970 | #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 1) 1971 | b->input = 0; 1972 | #endif 1973 | b->m.offset = i * buffer_size; 1974 | b->memory = V4L2_MEMORY_MMAP; 1975 | b->sequence = 0; 1976 | b->timestamp.tv_sec = 0; 1977 | b->timestamp.tv_usec = 0; 1978 | b->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 1979 | 1980 | do_gettimeofday(&b->timestamp); 1981 | } 1982 | dev->timeout_image_buffer = dev->buffers[0]; 1983 | dev->timeout_image_buffer.buffer.m.offset = MAX_BUFFERS * buffer_size; 1984 | MARK(); 1985 | } 1986 | 1987 | static int allocate_timeout_image(struct v4l2_loopback_device *dev) 1988 | { 1989 | MARK(); 1990 | if (dev->buffer_size <= 0) 1991 | return -EINVAL; 1992 | 1993 | if (dev->timeout_image == NULL) { 1994 | dev->timeout_image = v4l2l_vzalloc(dev->buffer_size); 1995 | if (dev->timeout_image == NULL) 1996 | return -ENOMEM; 1997 | } 1998 | return 0; 1999 | } 2000 | 2001 | /* fills and register video device */ 2002 | static void init_vdev(struct video_device *vdev, int nr) 2003 | { 2004 | MARK(); 2005 | snprintf(vdev->name, sizeof(vdev->name), "Loopback video device %X", nr); 2006 | 2007 | #ifdef V4L2LOOPBACK_WITH_STD 2008 | vdev->tvnorms = V4L2_STD_ALL; 2009 | vdev->current_norm = V4L2_STD_ALL; 2010 | #endif /* V4L2LOOPBACK_WITH_STD */ 2011 | 2012 | vdev->vfl_type = VFL_TYPE_GRABBER; 2013 | vdev->fops = &v4l2_loopback_fops; 2014 | vdev->ioctl_ops = &v4l2_loopback_ioctl_ops; 2015 | vdev->release = &video_device_release; 2016 | vdev->minor = -1; 2017 | if (debug > 1) 2018 | vdev->debug = V4L2_DEBUG_IOCTL | V4L2_DEBUG_IOCTL_ARG; 2019 | 2020 | /* since kernel-3.7, there is a new field 'vfl_dir' that has to be 2021 | * set to VFL_DIR_M2M for bidrectional devices */ 2022 | #ifdef VFL_DIR_M2M 2023 | vdev->vfl_dir = VFL_DIR_M2M; 2024 | #endif 2025 | 2026 | MARK(); 2027 | } 2028 | 2029 | /* init default capture parameters, only fps may be changed in future */ 2030 | static void init_capture_param(struct v4l2_captureparm *capture_param) 2031 | { 2032 | MARK(); 2033 | capture_param->capability = 0; 2034 | capture_param->capturemode = 0; 2035 | capture_param->extendedmode = 0; 2036 | capture_param->readbuffers = max_buffers; 2037 | capture_param->timeperframe.numerator = 1; 2038 | capture_param->timeperframe.denominator = 30; 2039 | } 2040 | 2041 | static void check_timers(struct v4l2_loopback_device *dev) 2042 | { 2043 | if (!dev->ready_for_capture) 2044 | return; 2045 | 2046 | if (dev->timeout_jiffies > 0 && !timer_pending(&dev->timeout_timer)) 2047 | mod_timer(&dev->timeout_timer, jiffies + dev->timeout_jiffies); 2048 | if (dev->sustain_framerate && !timer_pending(&dev->sustain_timer)) 2049 | mod_timer(&dev->sustain_timer, jiffies + dev->frame_jiffies * 3 / 2); 2050 | } 2051 | 2052 | static void sustain_timer_clb(unsigned long nr) 2053 | { 2054 | struct v4l2_loopback_device *dev = devs[nr]; 2055 | 2056 | spin_lock(&dev->lock); 2057 | if (dev->sustain_framerate) { 2058 | dev->reread_count++; 2059 | dprintkrw("reread: %d %d\n", dev->write_position, dev->reread_count); 2060 | if (dev->reread_count == 1) 2061 | mod_timer(&dev->sustain_timer, jiffies + max(1UL, dev->frame_jiffies / 2)); 2062 | else 2063 | mod_timer(&dev->sustain_timer, jiffies + dev->frame_jiffies); 2064 | wake_up_all(&dev->read_event); 2065 | } 2066 | spin_unlock(&dev->lock); 2067 | } 2068 | 2069 | static void timeout_timer_clb(unsigned long nr) 2070 | { 2071 | struct v4l2_loopback_device *dev = devs[nr]; 2072 | 2073 | spin_lock(&dev->lock); 2074 | if (dev->timeout_jiffies > 0) { 2075 | dev->timeout_happened = 1; 2076 | mod_timer(&dev->timeout_timer, jiffies + dev->timeout_jiffies); 2077 | wake_up_all(&dev->read_event); 2078 | } 2079 | spin_unlock(&dev->lock); 2080 | } 2081 | 2082 | /* init loopback main structure */ 2083 | static int v4l2_loopback_init(struct v4l2_loopback_device *dev, int nr) 2084 | { 2085 | int ret; 2086 | snprintf(dev->v4l2_dev.name, sizeof(dev->v4l2_dev.name), 2087 | "v4l2loopback-%03d", nr); 2088 | ret = v4l2_device_register(NULL, &dev->v4l2_dev); 2089 | if (ret) 2090 | return ret; 2091 | 2092 | MARK(); 2093 | dev->vdev = video_device_alloc(); 2094 | if (dev->vdev == NULL) { 2095 | v4l2_device_unregister(&dev->v4l2_dev); 2096 | return -ENOMEM; 2097 | } 2098 | 2099 | video_set_drvdata(dev->vdev, kzalloc(sizeof(struct v4l2loopback_private), GFP_KERNEL)); 2100 | if (video_get_drvdata(dev->vdev) == NULL) { 2101 | v4l2_device_unregister(&dev->v4l2_dev); 2102 | kfree(dev->vdev); 2103 | return -ENOMEM; 2104 | } 2105 | ((struct v4l2loopback_private *)video_get_drvdata(dev->vdev))->devicenr = nr; 2106 | 2107 | init_vdev(dev->vdev, nr); 2108 | dev->vdev->v4l2_dev = &dev->v4l2_dev; 2109 | init_capture_param(&dev->capture_param); 2110 | set_timeperframe(dev, &dev->capture_param.timeperframe); 2111 | dev->keep_format = 0; 2112 | dev->sustain_framerate = 0; 2113 | dev->buffers_number = max_buffers; 2114 | dev->used_buffers = max_buffers; 2115 | dev->max_openers = max_openers; 2116 | dev->write_position = 0; 2117 | spin_lock_init(&dev->lock); 2118 | INIT_LIST_HEAD(&dev->outbufs_list); 2119 | if (list_empty(&dev->outbufs_list)) { 2120 | int i; 2121 | 2122 | for (i = 0; i < dev->used_buffers; ++i) 2123 | list_add_tail(&dev->buffers[i].list_head, &dev->outbufs_list); 2124 | } 2125 | memset(dev->bufpos2index, 0, sizeof(dev->bufpos2index)); 2126 | atomic_set(&dev->open_count, 0); 2127 | dev->ready_for_capture = 0; 2128 | dev->ready_for_output = 1; 2129 | dev->announce_all_caps = (!exclusive_caps[nr]); 2130 | 2131 | dev->buffer_size = 0; 2132 | dev->image = NULL; 2133 | dev->imagesize = 0; 2134 | setup_timer(&dev->sustain_timer, sustain_timer_clb, nr); 2135 | dev->reread_count = 0; 2136 | setup_timer(&dev->timeout_timer, timeout_timer_clb, nr); 2137 | dev->timeout_jiffies = 0; 2138 | dev->timeout_image = NULL; 2139 | dev->timeout_happened = 0; 2140 | 2141 | /* FIXME set buffers to 0 */ 2142 | 2143 | /* Set initial format */ 2144 | dev->pix_format.width = 0; /* V4L2LOOPBACK_SIZE_DEFAULT_WIDTH; */ 2145 | dev->pix_format.height = 0; /* V4L2LOOPBACK_SIZE_DEFAULT_HEIGHT; */ 2146 | dev->pix_format.pixelformat = formats[0].fourcc; 2147 | dev->pix_format.colorspace = V4L2_COLORSPACE_SRGB; /* do we need to set this ? */ 2148 | dev->pix_format.field = V4L2_FIELD_NONE; 2149 | 2150 | dev->buffer_size = PAGE_ALIGN(dev->pix_format.sizeimage); 2151 | dprintk("buffer_size = %ld (=%d)\n", dev->buffer_size, dev->pix_format.sizeimage); 2152 | allocate_buffers(dev); 2153 | 2154 | init_waitqueue_head(&dev->read_event); 2155 | 2156 | MARK(); 2157 | return 0; 2158 | }; 2159 | 2160 | /* LINUX KERNEL */ 2161 | static const struct v4l2_file_operations v4l2_loopback_fops = { 2162 | .owner = THIS_MODULE, 2163 | .open = v4l2_loopback_open, 2164 | .release = v4l2_loopback_close, 2165 | .read = v4l2_loopback_read, 2166 | .write = v4l2_loopback_write, 2167 | .poll = v4l2_loopback_poll, 2168 | .mmap = v4l2_loopback_mmap, 2169 | .unlocked_ioctl = video_ioctl2, 2170 | }; 2171 | 2172 | static const struct v4l2_ioctl_ops v4l2_loopback_ioctl_ops = { 2173 | .vidioc_querycap = &vidioc_querycap, 2174 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29) 2175 | .vidioc_enum_framesizes = &vidioc_enum_framesizes, 2176 | .vidioc_enum_frameintervals = &vidioc_enum_frameintervals, 2177 | #endif 2178 | 2179 | .vidioc_queryctrl = &vidioc_queryctrl, 2180 | .vidioc_g_ctrl = &vidioc_g_ctrl, 2181 | .vidioc_s_ctrl = &vidioc_s_ctrl, 2182 | 2183 | .vidioc_enum_output = &vidioc_enum_output, 2184 | .vidioc_g_output = &vidioc_g_output, 2185 | .vidioc_s_output = &vidioc_s_output, 2186 | 2187 | .vidioc_enum_input = &vidioc_enum_input, 2188 | .vidioc_g_input = &vidioc_g_input, 2189 | .vidioc_s_input = &vidioc_s_input, 2190 | 2191 | .vidioc_enum_fmt_vid_cap = &vidioc_enum_fmt_cap, 2192 | .vidioc_g_fmt_vid_cap = &vidioc_g_fmt_cap, 2193 | .vidioc_s_fmt_vid_cap = &vidioc_s_fmt_cap, 2194 | .vidioc_try_fmt_vid_cap = &vidioc_try_fmt_cap, 2195 | 2196 | .vidioc_enum_fmt_vid_out = &vidioc_enum_fmt_out, 2197 | .vidioc_s_fmt_vid_out = &vidioc_s_fmt_out, 2198 | .vidioc_g_fmt_vid_out = &vidioc_g_fmt_out, 2199 | .vidioc_try_fmt_vid_out = &vidioc_try_fmt_out, 2200 | 2201 | #ifdef V4L2L_OVERLAY 2202 | .vidioc_s_fmt_vid_overlay = &vidioc_s_fmt_overlay, 2203 | .vidioc_g_fmt_vid_overlay = &vidioc_g_fmt_overlay, 2204 | #endif 2205 | 2206 | #ifdef V4L2LOOPBACK_WITH_STD 2207 | .vidioc_s_std = &vidioc_s_std, 2208 | .vidioc_g_std = &vidioc_g_std, 2209 | .vidioc_querystd = &vidioc_querystd, 2210 | #endif /* V4L2LOOPBACK_WITH_STD */ 2211 | 2212 | .vidioc_g_parm = &vidioc_g_parm, 2213 | .vidioc_s_parm = &vidioc_s_parm, 2214 | 2215 | .vidioc_reqbufs = &vidioc_reqbufs, 2216 | .vidioc_querybuf = &vidioc_querybuf, 2217 | .vidioc_qbuf = &vidioc_qbuf, 2218 | .vidioc_dqbuf = &vidioc_dqbuf, 2219 | 2220 | .vidioc_streamon = &vidioc_streamon, 2221 | .vidioc_streamoff = &vidioc_streamoff, 2222 | 2223 | #ifdef CONFIG_VIDEO_V4L1_COMPAT 2224 | .vidiocgmbuf = &vidiocgmbuf, 2225 | #endif 2226 | }; 2227 | 2228 | static void zero_devices(void) 2229 | { 2230 | int i; 2231 | 2232 | MARK(); 2233 | for (i = 0; i < MAX_DEVICES; i++) 2234 | devs[i] = NULL; 2235 | } 2236 | 2237 | static void free_devices(void) 2238 | { 2239 | int i; 2240 | 2241 | MARK(); 2242 | for (i = 0; i < devices; i++) { 2243 | if (NULL != devs[i]) { 2244 | free_buffers(devs[i]); 2245 | v4l2loopback_remove_sysfs(devs[i]->vdev); 2246 | kfree(video_get_drvdata(devs[i]->vdev)); 2247 | video_unregister_device(devs[i]->vdev); 2248 | v4l2_device_unregister(&devs[i]->v4l2_dev); 2249 | kfree(devs[i]); 2250 | devs[i] = NULL; 2251 | } 2252 | } 2253 | } 2254 | 2255 | int __init init_module(void) 2256 | { 2257 | int ret; 2258 | int i; 2259 | MARK(); 2260 | 2261 | zero_devices(); 2262 | if (devices < 0) { 2263 | devices = 1; 2264 | 2265 | /* try guessing the devices from the "video_nr" parameter */ 2266 | for (i = MAX_DEVICES - 1; i >= 0; i--) { 2267 | if (video_nr[i] >= 0) { 2268 | devices = i + 1; 2269 | break; 2270 | } 2271 | } 2272 | } 2273 | 2274 | if (devices > MAX_DEVICES) { 2275 | devices = MAX_DEVICES; 2276 | printk(KERN_INFO "v4l2loopback: number of devices is limited to: %d\n", MAX_DEVICES); 2277 | } 2278 | 2279 | if (max_buffers > MAX_BUFFERS) { 2280 | max_buffers = MAX_BUFFERS; 2281 | printk(KERN_INFO "v4l2loopback: number of buffers is limited to: %d\n", MAX_BUFFERS); 2282 | } 2283 | 2284 | if (max_openers < 0) { 2285 | printk(KERN_INFO "v4l2loopback: allowing %d openers rather than %d\n", 2, max_openers); 2286 | max_openers = 2; 2287 | } 2288 | 2289 | if (max_width < 1) { 2290 | max_width = V4L2LOOPBACK_SIZE_MAX_WIDTH; 2291 | printk(KERN_INFO "v4l2loopback: using max_width %d\n", max_width); 2292 | } 2293 | if (max_height < 1) { 2294 | max_height = V4L2LOOPBACK_SIZE_MAX_HEIGHT; 2295 | printk(KERN_INFO "v4l2loopback: using max_height %d\n", max_height); 2296 | } 2297 | 2298 | /* kfree on module release */ 2299 | for (i = 0; i < devices; i++) { 2300 | dprintk("creating v4l2loopback-device #%d\n", i); 2301 | devs[i] = kzalloc(sizeof(*devs[i]), GFP_KERNEL); 2302 | if (devs[i] == NULL) { 2303 | free_devices(); 2304 | return -ENOMEM; 2305 | } 2306 | ret = v4l2_loopback_init(devs[i], i); 2307 | if (ret < 0) { 2308 | free_devices(); 2309 | return ret; 2310 | } 2311 | /* register the device -> it creates /dev/video* */ 2312 | if (video_register_device(devs[i]->vdev, VFL_TYPE_GRABBER, video_nr[i]) < 0) { 2313 | video_device_release(devs[i]->vdev); 2314 | printk(KERN_ERR "v4l2loopback: failed video_register_device()\n"); 2315 | free_devices(); 2316 | return -EFAULT; 2317 | } 2318 | v4l2loopback_create_sysfs(devs[i]->vdev); 2319 | } 2320 | 2321 | dprintk("module installed\n"); 2322 | 2323 | printk(KERN_INFO "v4l2loopback driver version %d.%d.%d loaded\n", 2324 | (V4L2LOOPBACK_VERSION_CODE >> 16) & 0xff, 2325 | (V4L2LOOPBACK_VERSION_CODE >> 8) & 0xff, 2326 | (V4L2LOOPBACK_VERSION_CODE) & 0xff); 2327 | 2328 | return 0; 2329 | } 2330 | 2331 | void __exit cleanup_module(void) 2332 | { 2333 | MARK(); 2334 | /* unregister the device -> it deletes /dev/video* */ 2335 | free_devices(); 2336 | dprintk("module removed\n"); 2337 | } 2338 | 2339 | -------------------------------------------------------------------------------- /vm_dump_test/.cproject: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /vm_dump_test/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | vm_dump 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.cdt.managedbuilder.core.genmakebuilder 10 | clean,full,incremental, 11 | 12 | 13 | 14 | 15 | org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder 16 | full,incremental, 17 | 18 | 19 | 20 | 21 | 22 | org.eclipse.cdt.core.cnature 23 | org.eclipse.cdt.core.ccnature 24 | org.eclipse.cdt.managedbuilder.core.managedBuildNature 25 | org.eclipse.cdt.managedbuilder.core.ScannerConfigNature 26 | 27 | 28 | -------------------------------------------------------------------------------- /vm_dump_test/Makefile: -------------------------------------------------------------------------------- 1 | ifndef verbose 2 | SILENT = @ 3 | endif 4 | VERSION = 0.1 5 | 6 | #SYSROOT=/home/hf/android-ndk-r8/platforms/android-14/arch-arm 7 | #CC = /home/hf/android-ndk-r8/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86/bin/arm-linux-androideabi-gcc --sysroot=$(SYSROOT) 8 | #CXX = /home/hf/android-ndk-r8/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86/bin/arm-linux-androideabi-g++ --sysroot=$(SYSROOT) 9 | #AR = /home/hf/android-ndk-r8/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86/bin/arm-linux-androideabi-ar --sysroot=$(SYSROOT) 10 | SYSROOT=$(ANDROID_NDK_ROOT)/platforms/android-14/arch-arm 11 | CC = $(ANDROID_NDK_ROOT)/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86/bin/arm-linux-androideabi-gcc --sysroot=$(SYSROOT) 12 | CXX = $(ANDROID_NDK_ROOT)/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86/bin/arm-linux-androideabi-g++ --sysroot=$(SYSROOT) 13 | AR = $(ANDROID_NDK_ROOT)/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86/bin/arm-linux-androideabi-ar 14 | 15 | #CC = ../toolchain/crosstools/bin/mipsel-linux-gcc 16 | #CXX = ../toolchain/crosstools/bin/mipsel-linux-g++ 17 | #AR = ../toolchain/crosstools/bin/mipsel-linux-ar 18 | 19 | #CC = gcc 20 | #CXX = g++ 21 | #AR = ar 22 | 23 | #CC = /home/andyhsieh/prj/Freescale/arm-eabi-4.4.0/bin/gcc/arm-eabi-gcc 24 | #CXX = /home/andyhsieh/prj/Freescale/arm-eabi-4.4.0/bin/arm-eabi-g++ 25 | #AR = /home/andyhsieh/prj/Freescale/arm-eabi-4.4.0/bin/arm-eabi-ar 26 | 27 | #CC = arm-fsl-linux-gnueabi-gcc 28 | #CXX = arm-fsl-linux-gnueabi-g++ 29 | #AR = arm-fsl-linux-gnueabi-ar 30 | #LIBS = -laituvc_fsl 31 | 32 | ifndef CC 33 | CC = gcc 34 | endif 35 | 36 | ifndef CXX 37 | CXX = g++ 38 | endif 39 | 40 | ifndef AR 41 | AR = ar 42 | endif 43 | 44 | TARGETDIR = 45 | TARGET = $(TARGETDIR)bin/vmc_test 46 | DEFINES += -D_DEBUG -DDEBUG -DENABLE_DEBUG 47 | CPPFLAGS += -MMD -MP $(DEFINES) $(INCLUDES) -DLINUX -DVERSION=\"$(VERSION)\" 48 | CFLAGS += $(CPPFLAGS) $(ARCH) -Wall -g 49 | CXXFLAGS += $(CFLAGS) -fno-rtti -fno-exceptions -g 50 | #LDFLAGS += -llog 51 | LIBS += 52 | RESFLAGS += $(DEFINES) $(INCLUDES) 53 | LDDEPS += 54 | SRC = V4l2Capture.cpp main.cpp 55 | OBJECTS = V4l2Capture.o main.o 56 | 57 | all: 58 | $(CXX) -c $(SRC) $(INCLUDES) $(CXXFLAGS) 59 | $(CXX) -o $(TARGET) $(OBJECTS) -L./ $(LIBS) $(LDFLAGS) 60 | $(AR) -rc libzxwcapture.a $(OBJECTS) 61 | 62 | 63 | clean: 64 | rm -f $(OBJECTS) $(TARGET) 65 | 66 | -------------------------------------------------------------------------------- /vm_dump_test/Makefile_o: -------------------------------------------------------------------------------- 1 | ifndef verbose 2 | SILENT = @ 3 | endif 4 | 5 | 6 | SYSROOT=/home/hf/android-ndk-r8/platforms/android-14/arch-arm 7 | CC = /home/hf/android-ndk-r8/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86/bin/arm-linux-androideabi-gcc --sysroot=$(SYSROOT) 8 | CXX = /home/hf/android-ndk-r8/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86/bin/arm-linux-androideabi-g++ --sysroot=$(SYSROOT) 9 | AR = /home/hf/android-ndk-r8/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86/bin/arm-linux-androideabi-ar --sysroot=$(SYSROOT) 10 | 11 | #CC = ../toolchain/crosstools/bin/mipsel-linux-gcc 12 | #CXX = ../toolchain/crosstools/bin/mipsel-linux-g++ 13 | #AR = ../toolchain/crosstools/bin/mipsel-linux-ar 14 | 15 | #CC = /home/andyhsieh/prj/Freescale/arm-eabi-4.4.0/bin/gcc/arm-eabi-gcc 16 | #CXX = /home/andyhsieh/prj/Freescale/arm-eabi-4.4.0/bin/arm-eabi-g++ 17 | #AR = /home/andyhsieh/prj/Freescale/arm-eabi-4.4.0/bin/arm-eabi-ar 18 | 19 | #CC = arm-fsl-linux-gnueabi-gcc 20 | #CXX = arm-fsl-linux-gnueabi-g++ 21 | #AR = arm-fsl-linux-gnueabi-ar 22 | #LIBS = -laituvc_fsl 23 | 24 | ifndef CC 25 | CC = gcc 26 | endif 27 | 28 | ifndef CXX 29 | CXX = g++ 30 | endif 31 | 32 | ifndef AR 33 | AR = ar 34 | endif 35 | 36 | TARGETDIR = 37 | TARGET = $(TARGETDIR)bin/VideoDevDump 38 | DEFINES += -D_DEBUG -DDEBUG 39 | CPPFLAGS += -MMD -MP $(DEFINES) $(INCLUDES) 40 | CFLAGS += $(CPPFLAGS) $(ARCH) -Wall 41 | CXXFLAGS += $(CFLAGS) -fno-rtti -fno-exceptions 42 | LDFLAGS += 43 | LIBS += 44 | RESFLAGS += $(DEFINES) $(INCLUDES) 45 | LDDEPS += 46 | SRC = vm.cpp 47 | OBJECTS = vm.o 48 | 49 | all: 50 | $(CXX) -c $(SRC) $(INCLUDES) $(CXXFLAGS) 51 | $(CXX) -o $(TARGET) $(OBJECTS) -L./ $(LIBS) 52 | 53 | clean: 54 | rm -f $(OBJECTS) $(TARGET) 55 | 56 | -------------------------------------------------------------------------------- /vm_dump_test/MediaSample.hpp: -------------------------------------------------------------------------------- 1 | #ifndef MEDIASAMPLE_H 2 | #define MEDIASAMPLE_H 3 | 4 | #include 5 | class MediaSample 6 | { 7 | public: 8 | MediaSample() 9 | :is_ext_buf(0) 10 | ,buf(0) 11 | ,buf_used(0) 12 | ,buf_size(0) 13 | {} 14 | virtual ~MediaSample() 15 | { 16 | if( is_ext_buf==false && buf!=0) 17 | delete buf; 18 | } 19 | bool AllocBuffer(uint32_t size,uint8_t* ext_buf=0) 20 | { 21 | if( is_ext_buf==false && buf!=0) 22 | { 23 | delete buf; 24 | buf = 0; 25 | } 26 | 27 | if(ext_buf) 28 | { 29 | is_ext_buf = true; 30 | buf_size = size; 31 | buf_used = 0; 32 | buf = ext_buf; 33 | } 34 | else 35 | { 36 | is_ext_buf = false; 37 | buf_size = size; 38 | buf_used = 0; 39 | buf = new uint8_t[size]; 40 | } 41 | return true; 42 | } 43 | 44 | bool SetSampleSize(uint32_t size) 45 | { 46 | if(buf) 47 | { 48 | buf_used = size; 49 | return true; 50 | } 51 | else 52 | return false; 53 | } 54 | 55 | uint32_t GetSampleSize() 56 | { 57 | return buf_used; 58 | } 59 | 60 | uint32_t GetBufferSize() 61 | { 62 | return buf_size; 63 | } 64 | 65 | uint8_t* GetBuffer() 66 | { 67 | return buf; 68 | } 69 | private: 70 | bool is_ext_buf; 71 | uint8_t *buf; 72 | uint32_t buf_used; 73 | uint32_t buf_size; 74 | }; 75 | 76 | #endif 77 | -------------------------------------------------------------------------------- /vm_dump_test/V4l2Capture.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2007-2009 Skype Technologies S.A. Confidential and proprietary 3 | * 4 | * All intellectual property rights, including but not limited to copyrights, 5 | * trademarks and patents, as well as know how and trade secrets contained 6 | * in, relating to, or arising from the internet telephony software of Skype 7 | * Limited (including its affiliates, "Skype"), including without limitation 8 | * this source code, Skype API and related material of such software 9 | * proprietary to Skype and/or its licensors ("IP Rights") are and shall 10 | * remain the exclusive property of Skype and/or its licensors. The recipient 11 | * hereby acknowledges and agrees that any unauthorized use of the IP Rights 12 | * is a violation of intellectual property laws. 13 | * 14 | * Skype reserves all rights and may take legal action against infringers of 15 | * IP Rights. 16 | * 17 | * The recipient agrees not to remove, obscure, make illegible or alter any 18 | * notices or indications of the IP Rights and/or Skype's rights and ownership 19 | * thereof. 20 | */ 21 | #include "V4l2Capture.hpp" 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | 37 | #undef LOG_PREFIX 38 | #define LOG_PREFIX "V4l2Capture:" 39 | 40 | #ifdef ANDROID 41 | #include 42 | #define THIS_FILE "V4l2Capture.cpp" 43 | #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, THIS_FILE, __VA_ARGS__) 44 | #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, THIS_FILE, __VA_ARGS__) 45 | #else 46 | #define LOGE(...) 47 | #define LOGD(...) 48 | #endif 49 | #include "debugging.hpp" 50 | 51 | #define CAP_DBG DBG 52 | 53 | #define NB_BUFFER 16 54 | 55 | 56 | 57 | #define V4L2_CTRL_CLASS_VM 0x00dd0000 58 | #define V4L2_CID_VM_EXT_BASE (V4L2_CTRL_CLASS_VM | 0x900) 59 | 60 | 61 | 62 | 63 | //PROPSETID_VM_XU_CONTROL 64 | //a917c75d-4119-11da-ae0e000d56ac7b4c 65 | 66 | #define PROPSETID_VM_XU_CONTROL { \ 67 | 0x5d, 0xc7, 0x17, 0xa9, 0x19, 0x41, 0xda, 0x11, \ 68 | 0xae, 0x0e, 0x00, 0x0d, 0x56, 0xac, 0x7b, 0x4c \ 69 | } 70 | 71 | #define UVC_GUID_VM_EXT { \ 72 | 0xbb, 0xae, 0xde, 0xe3, 0xec, 0xc2, 0x42, 0x4d, \ 73 | 0x80, 0x2c, 0x72, 0xf2, 0xeb, 0x3d, 0xfb, 0x57 \ 74 | } 75 | 76 | #define GUID_SIZE 16 77 | 78 | 79 | #define EU_VMH264_CONTROL 0x1A 80 | 81 | #define UVC_SET_CUR 0x01 82 | #define UVC_GET_CUR 0x81 83 | #define UVC_GET_MIN 0x82 84 | #define UVC_GET_MAX 0x83 85 | #define UVC_GET_RES 0x84 86 | #define UVC_GET_LEN 0x85 87 | #define UVC_GET_INFO 0x86 88 | #define UVC_GET_DEF 0x87 89 | 90 | struct FrameBuf { 91 | void *start; 92 | size_t length; 93 | }; 94 | 95 | V4l2Capture::V4l2Capture(const char *devName) : 96 | m_pFrameBuf(NULL), 97 | m_pDevName(devName), 98 | m_IsConfigured(0), 99 | m_NBuffers(0) 100 | { 101 | OpenDevice(); 102 | } 103 | 104 | V4l2Capture::~V4l2Capture() 105 | { 106 | if (m_IsConfigured) 107 | UnConfigureDev(); 108 | 109 | CloseDevice(); 110 | } 111 | 112 | #define CLEAR(x) memset (&(x), 0, sizeof (x)) 113 | 114 | static int xioctl(int fd, int request, void * arg) 115 | { 116 | int r; 117 | 118 | do { 119 | r = ioctl(fd, request, arg); 120 | } while (-1 == r && EINTR == errno); 121 | return r; 122 | } 123 | 124 | void V4l2Capture::OpenDevice() 125 | { 126 | struct stat st; 127 | 128 | if (-1 == stat(m_pDevName, &st)) { 129 | LOGD("Cannot identify '%s': %d, %s\n", m_pDevName, errno, 130 | strerror(errno)); 131 | FATAL("Cannot identify '%s': %d, %s\n", m_pDevName, errno, 132 | strerror(errno)); 133 | } 134 | 135 | if (!S_ISCHR(st.st_mode)) { 136 | LOGD("%s is no device\n", m_pDevName); 137 | FATAL("%s is no device\n", m_pDevName); 138 | } 139 | 140 | m_Fd = open(m_pDevName, O_RDWR /* required *//*| O_NONBLOCK*/, 0); 141 | //m_Fd = open(m_pDevName, O_RDWR , 0); 142 | 143 | if (-1 == m_Fd) { 144 | LOGD("Cannot open '%s': %d, %s\n", m_pDevName, errno, 145 | strerror(errno)); 146 | FATAL("Cannot open '%s': %d, %s\n", m_pDevName, errno, 147 | strerror(errno)); 148 | } 149 | } 150 | 151 | void V4l2Capture::CloseDevice() 152 | { 153 | if(m_Fd<0) 154 | return; 155 | 156 | if (-1 == close(m_Fd)) 157 | FATAL("close"); 158 | 159 | m_Fd = -1; 160 | } 161 | 162 | 163 | //#include "IAitH264Cam.h" 164 | bool V4l2Capture::SetFramerate(int fps) 165 | {/* 166 | struct v4l2_streamparm parm; 167 | memset(&parm, 0, sizeof(parm)); 168 | parm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 169 | 170 | // first get current values 171 | if (xioctl(m_Fd, VIDIOC_G_PARM, &parm) == 0) { 172 | 173 | DBG("current framerate params: numerator %d denominator, %d", parm.parm.capture.timeperframe.numerator, 174 | parm.parm.capture.timeperframe.denominator); 175 | 176 | DBG("SetFramerate VIDIOC_G_PARM: %d", fps); 177 | 178 | // change rate 179 | // time per frame is numerator / denominator in seconds 180 | parm.parm.capture.timeperframe.numerator = 1; 181 | parm.parm.capture.timeperframe.denominator = fps; 182 | 183 | // set new values 184 | if(-1 == xioctl(m_Fd, VIDIOC_S_PARM, &parm)) { 185 | ERROR("V4l2Capture: Failed to set streamparm: %s\n", strerror(errno)); 186 | return false; 187 | } 188 | // now comes the special hack for pwc driver... 189 | // http://osdir.com/ml/drivers.pwc/2005-11/msg00001.html 190 | } else { 191 | DBG("V4l2Capture: Failed to get streamparm: %s, trying pwc driver hack\n", strerror(errno)); 192 | 193 | struct v4l2_format fmt; 194 | CLEAR(fmt); 195 | fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 196 | 197 | if (-1 == xioctl(m_Fd, VIDIOC_G_FMT, &fmt)) { 198 | ERROR("V4l2Capture: VIDIOC_G_FMT failed %s\n", strerror(errno)); 199 | return false; 200 | } 201 | 202 | #define PWC_FPS_SHIFT 16 203 | fmt.fmt.pix.priv = (fps << PWC_FPS_SHIFT); 204 | if (-1 == xioctl(m_Fd, VIDIOC_S_FMT, &fmt)) { 205 | ERROR("V4l2Capture: VIDIOC_S_FMT failed %s\n", strerror(errno)); 206 | return false; 207 | } 208 | }*/ 209 | 210 | //Truman@100812 211 | //HRESULT STDMETHODCALLTYPE SetFrameRate(BYTE rate); 212 | //SetFrameRate(fps); 213 | return true; 214 | } 215 | int V4l2Capture::SetH264BitRate(unsigned long bitrate ) 216 | { 217 | struct uvc_xu_control_query control_s; 218 | int err; 219 | short len = 0; 220 | char DMA[8]; 221 | 222 | LOGD("v4l2 set bitrate: %ul", bitrate); 223 | control_s.unit = 4; 224 | control_s.selector = EU_VMH264_CONTROL; 225 | control_s.size = 8; 226 | control_s.query = UVC_SET_CUR; 227 | memset(DMA, 0, 8); 228 | DMA[0] = 0x1; 229 | DMA[1] = 0; 230 | memcpy(&DMA[2], &bitrate, 4); 231 | DMA[6] = 30; 232 | 233 | control_s.data = (__u8*)DMA; 234 | if ((err = xioctl (m_Fd, UVCIOC_CTRL_QUERY, &control_s)) < 0) { 235 | LOGE ("ioctl set control error %d\n", err); 236 | return -1; 237 | } 238 | return err; 239 | 240 | } 241 | bool V4l2Capture::SetFormat(uint32_t width, uint32_t height, uint32_t pixFmt) { 242 | struct v4l2_format fmt; 243 | 244 | CLEAR(fmt); 245 | 246 | fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 247 | fmt.fmt.pix.width = width; 248 | fmt.fmt.pix.height = height; 249 | fmt.fmt.pix.pixelformat = pixFmt; 250 | //fmt.fmt.pix.field = V4L2_FIELD_INTERLACED; 251 | fmt.fmt.pix.field = V4L2_FIELD_ANY; 252 | 253 | if (-1 == xioctl(m_Fd, VIDIOC_S_FMT, &fmt)) 254 | return false; 255 | 256 | CAP_DBG("width: %d, height: %d, size: %d, bpl: %d\n", fmt.fmt.pix.width, fmt.fmt.pix.height, fmt.fmt.pix.sizeimage, fmt.fmt.pix.bytesperline); 257 | 258 | m_FrameSize = fmt.fmt.pix.sizeimage; 259 | 260 | /* Note VIDIOC_S_FMT may change width and height. */ 261 | if (fmt.fmt.pix.width != width || fmt.fmt.pix.height != height) { 262 | ERROR("VIDIOC_S_FMT changed width or height: wanted %d %d, got %d %d", width, 263 | height, fmt.fmt.pix.width, fmt.fmt.pix.height); 264 | return false; 265 | } 266 | 267 | return true; 268 | } 269 | 270 | bool V4l2Capture::ConfigureDev(uint32_t width, uint32_t height, uint32_t pixFmt, uint32_t framerate) 271 | { 272 | struct v4l2_capability cap; 273 | 274 | if (-1 == xioctl(m_Fd, VIDIOC_QUERYCAP, &cap)) { 275 | if (EINVAL== errno) { 276 | LOGD("%s is no V4L2 device\n", m_pDevName); 277 | FATAL("%s is no V4L2 device\n", m_pDevName); 278 | } else { 279 | LOGD("VIDIOC_QUERYCAP failed"); 280 | FATAL("VIDIOC_QUERYCAP failed"); 281 | } 282 | } 283 | 284 | if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) { 285 | LOGD("%s is no video capture device\n", m_pDevName); 286 | FATAL("%s is no video capture device\n", m_pDevName); 287 | } 288 | 289 | if (!(cap.capabilities & V4L2_CAP_STREAMING)) { 290 | LOGD("%s does not support streaming i/o\n", m_pDevName); 291 | FATAL("%s does not support streaming i/o\n", m_pDevName); 292 | } 293 | 294 | if (!SetFormat(width, height, pixFmt)) { 295 | LOGD("SetFormat failed"); 296 | ERROR("SetFormat failed"); 297 | return false; 298 | } 299 | 300 | if (!SetFramerate(framerate)) { 301 | ERROR("SetFramerate failed"); 302 | return false; 303 | } 304 | 305 | struct v4l2_requestbuffers req; 306 | 307 | CLEAR (req); 308 | 309 | req.count = 12; 310 | req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 311 | req.memory = V4L2_MEMORY_MMAP; 312 | 313 | if (-1 == xioctl (m_Fd, VIDIOC_REQBUFS, &req)) { 314 | if (EINVAL == errno) { 315 | LOGD("%s does not support " 316 | "memory mapping\n", m_pDevName); 317 | FATAL("%s does not support " 318 | "memory mapping\n", m_pDevName); 319 | } else { 320 | LOGD("VIDIOC_REQBUFS failed"); 321 | FATAL("VIDIOC_REQBUFS failed"); 322 | } 323 | } 324 | 325 | CAP_DBG("req.count: %d", req.count); 326 | if (req.count < 2) { 327 | LOGD("Insufficient buffer memory on %s\n", 328 | m_pDevName); 329 | FATAL("Insufficient buffer memory on %s\n", 330 | m_pDevName); 331 | } 332 | 333 | m_pFrameBuf = (FrameBuf *) calloc (req.count, sizeof (*m_pFrameBuf)); 334 | 335 | if (!m_pFrameBuf) { 336 | LOGD("Out of memory\n"); 337 | FATAL("Out of memory\n"); 338 | } 339 | 340 | for (m_NBuffers = 0; m_NBuffers < req.count; ++m_NBuffers) { 341 | struct v4l2_buffer buf; 342 | 343 | CLEAR (buf); 344 | 345 | buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 346 | buf.memory = V4L2_MEMORY_MMAP; 347 | buf.index = m_NBuffers; 348 | 349 | if (-1 == xioctl (m_Fd, VIDIOC_QUERYBUF, &buf)) { 350 | LOGD("VIDIOC_QUERYBUF failed"); 351 | FATAL("VIDIOC_QUERYBUF failed"); 352 | } 353 | 354 | m_pFrameBuf[m_NBuffers].length = buf.length; 355 | m_pFrameBuf[m_NBuffers].start = 356 | mmap (NULL /* start anywhere */, 357 | buf.length, 358 | PROT_READ | PROT_WRITE /* required */, 359 | MAP_SHARED /* recommended */, 360 | m_Fd, buf.m.offset); 361 | 362 | if (MAP_FAILED == m_pFrameBuf[m_NBuffers].start) { 363 | LOGD("mmap failed"); 364 | FATAL("mmap"); 365 | } 366 | } 367 | 368 | StartCapturing(); 369 | m_IsConfigured = 1; 370 | return true; 371 | } 372 | 373 | void V4l2Capture::UnConfigureDev() 374 | { 375 | uint32_t i; 376 | 377 | m_IsConfigured = 0; 378 | StopCapturing(); 379 | 380 | for (i = 0; i < m_NBuffers; ++i) 381 | if (-1 == munmap(m_pFrameBuf[i].start, m_pFrameBuf[i].length)) 382 | FATAL("munmap"); 383 | free(m_pFrameBuf); 384 | } 385 | 386 | void V4l2Capture::StartCapturing() 387 | { 388 | uint32_t i; 389 | enum v4l2_buf_type type; 390 | 391 | for (i = 0; i < m_NBuffers; ++i) { 392 | struct v4l2_buffer buf; 393 | 394 | CLEAR (buf); 395 | 396 | buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 397 | buf.memory = V4L2_MEMORY_MMAP; 398 | buf.index = i; 399 | 400 | if (-1 == xioctl(m_Fd, VIDIOC_QBUF, &buf)) 401 | FATAL("VIDIOC_QBUF failed"); 402 | } 403 | 404 | type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 405 | 406 | if (-1 == xioctl(m_Fd, VIDIOC_STREAMON, &type)) 407 | FATAL("VIDIOC_STREAMON failed"); 408 | } 409 | 410 | void V4l2Capture::StopCapturing() 411 | { 412 | enum v4l2_buf_type type; 413 | 414 | type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 415 | 416 | if (-1 == xioctl(m_Fd, VIDIOC_STREAMOFF, &type)) 417 | FATAL("VIDIOC_STREAMOFF failed"); 418 | } 419 | 420 | void V4l2Capture::ReadFrame(struct v4l2_buffer *buf) 421 | { 422 | if (!m_IsConfigured) { 423 | ERROR("Not configured"); 424 | return; 425 | } 426 | for (;;) { 427 | fd_set fds; 428 | struct timeval tv; 429 | int r; 430 | 431 | FD_ZERO (&fds); 432 | FD_SET (m_Fd, &fds); 433 | 434 | /* Timeout. */ 435 | tv.tv_sec = 5; 436 | tv.tv_usec = 0; 437 | //LOGD("before sleep\n"); 438 | //sleep(3); 439 | //LOGD("after sleep\n"); 440 | r = select(m_Fd + 1, &fds, NULL, NULL, &tv); 441 | //LOGD("after select, r = %d\n", r); 442 | if (-1 == r) { 443 | if (EINTR== errno) 444 | continue; 445 | LOGE("read frame, select failed"); 446 | FATAL("select failed"); 447 | } 448 | 449 | if (0 == r) { 450 | LOGE("read frame, select timeout\n"); 451 | FATAL("read frame, select timeout\n"); 452 | } 453 | 454 | CLEAR (*buf); 455 | 456 | buf->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 457 | buf->memory = V4L2_MEMORY_MMAP; 458 | 459 | r = xioctl (m_Fd, VIDIOC_DQBUF, buf); 460 | //printf("after VIDIOC_DQBUF, r = %d, errno = %d\n", r, errno); 461 | if (-1 == r) { 462 | switch (errno) { 463 | case EAGAIN: 464 | continue; 465 | case EIO: 466 | FATAL("VIDIOC_DQBUF returned EIO"); 467 | WARN("VIDIOC_DQBUF returned EIO"); 468 | return; 469 | default: 470 | LOGE("VIDIOC_DQBUF failed"); 471 | FATAL("VIDIOC_DQBUF failed"); 472 | } 473 | } else { 474 | assert (buf->index < m_NBuffers); 475 | return; 476 | } 477 | } 478 | } 479 | 480 | void V4l2Capture::CaptureFrame(uint8_t *frameBuf, uint32_t *frameBufLen) 481 | { 482 | struct v4l2_buffer buf; 483 | 484 | ReadFrame(&buf); 485 | LOGD("cp buf size:%d, frameBufLen: %p", buf.bytesused, frameBufLen); 486 | memcpy(frameBuf, m_pFrameBuf[buf.index].start, buf.bytesused); 487 | 488 | if (-1 == xioctl(m_Fd, VIDIOC_QBUF, &buf)) 489 | FATAL("VIDIOC_QBUF failed"); 490 | 491 | *frameBufLen = buf.bytesused; 492 | } 493 | 494 | int V4l2Capture::CaptureFrame(MediaSample &sample) 495 | { 496 | struct v4l2_buffer buf; 497 | 498 | ReadFrame(&buf); 499 | //CAP_DBG("V4l2Capture: Got a frame from device. \r\n"); 500 | //assert(m_FrameSize == frameBufLen); 501 | 502 | //memcpy(frameBuf, m_pFrameBuf[buf.index].start, m_FrameSize); 503 | //if(sample.GetBufferSize() >= m_FrameSize) 504 | if(sample.GetBufferSize() >= buf.bytesused) 505 | { 506 | memcpy(sample.GetBuffer(),m_pFrameBuf[buf.index].start,buf.bytesused); 507 | //sample.SetSampleSize(m_FrameSize); 508 | sample.SetSampleSize(buf.bytesused); 509 | //CAP_DBG("Frame size = 0x%X \r\n",sample.GetSampleSize()); 510 | if (-1 == xioctl(m_Fd, VIDIOC_QBUF, &buf)) 511 | FATAL("VIDIOC_QBUF failed"); 512 | m_FrameSize = buf.bytesused; 513 | return m_FrameSize; 514 | } 515 | else 516 | { 517 | if (-1 == xioctl(m_Fd, VIDIOC_QBUF, &buf)) 518 | FATAL("VIDIOC_QBUF failed"); 519 | return 0; 520 | } 521 | } 522 | -------------------------------------------------------------------------------- /vm_dump_test/V4l2Capture.d: -------------------------------------------------------------------------------- 1 | V4l2Capture.o: V4l2Capture.cpp V4l2Capture.hpp MediaSample.hpp \ 2 | debugging.hpp 3 | 4 | V4l2Capture.hpp: 5 | 6 | MediaSample.hpp: 7 | 8 | debugging.hpp: 9 | -------------------------------------------------------------------------------- /vm_dump_test/V4l2Capture.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2007-2009 Skype Technologies S.A. Confidential and proprietary 3 | * 4 | * All intellectual property rights, including but not limited to copyrights, 5 | * trademarks and patents, as well as know how and trade secrets contained 6 | * in, relating to, or arising from the internet telephony software of Skype 7 | * Limited (including its affiliates, "Skype"), including without limitation 8 | * this source code, Skype API and related material of such software 9 | * proprietary to Skype and/or its licensors ("IP Rights") are and shall 10 | * remain the exclusive property of Skype and/or its licensors. The recipient 11 | * hereby acknowledges and agrees that any unauthorized use of the IP Rights 12 | * is a violation of intellectual property laws. 13 | * 14 | * Skype reserves all rights and may take legal action against infringers of 15 | * IP Rights. 16 | * 17 | * The recipient agrees not to remove, obscure, make illegible or alter any 18 | * notices or indications of the IP Rights and/or Skype's rights and ownership 19 | * thereof. 20 | */ 21 | 22 | #ifndef V4L2CAPTURE_HPP_ 23 | #define V4L2CAPTURE_HPP_ 24 | 25 | #include 26 | #include "MediaSample.hpp" 27 | 28 | struct FrameBuf; 29 | 30 | class V4l2Capture 31 | { 32 | public: 33 | V4l2Capture(const char *devName); 34 | ~V4l2Capture(); 35 | bool ConfigureDev(uint32_t width, uint32_t height, uint32_t pixFmt, uint32_t framerate); 36 | void UnConfigureDev(); 37 | void CaptureFrame(uint8_t *frameBuf, uint32_t *frameBufLen); 38 | int CaptureFrame(MediaSample &sample); 39 | int GetDevHandle(){return m_Fd;} 40 | int m_Fd; 41 | int SetH264BitRate(unsigned long bitrate ); 42 | 43 | protected: 44 | FrameBuf *m_pFrameBuf; 45 | 46 | private: 47 | void OpenDevice(); 48 | void CloseDevice(); 49 | bool SetFormat(uint32_t width, uint32_t height, uint32_t pixFmt); 50 | void ReadFrame(struct v4l2_buffer *buf); 51 | void StartCapturing(); 52 | void StopCapturing(); 53 | bool SetFramerate(int fps); 54 | const char *m_pDevName; 55 | int m_IsConfigured; 56 | uint32_t m_FrameSize; 57 | uint32_t m_NBuffers; 58 | }; 59 | 60 | 61 | #endif /* V4L2CAPTURE_HPP_ */ 62 | -------------------------------------------------------------------------------- /vm_dump_test/V4l2CaptureInterface.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | //#include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | 20 | #include "V4l2Capture.hpp" 21 | #include "V4l2CaptureInterface.h" 22 | 23 | #define ST_YUY2 41 24 | #define ST_H264 43 25 | 26 | #define YUY2_WIDTH 640 27 | #define YUY2_HEIGHT 480 28 | #define H264_WIDTH 640 29 | #define H264_HEIGHT 480 30 | 31 | #define REC_FRAMES 15*60 //10 sec 32 | #define BITRATE 256 //2500KBPS 33 | #define FPS 10 //30 FPS 34 | 35 | 36 | #include 37 | #define THIS_FILE "V4l2CaptureInterface.cpp" 38 | #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, THIS_FILE, __VA_ARGS__) 39 | #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, THIS_FILE, __VA_ARGS__) 40 | //#define LOGE(...) 41 | //#define LOGD(...) 42 | 43 | using namespace std; 44 | 45 | struct ZXW_Capture { 46 | V4l2Capture *v4l2cap; 47 | int width; 48 | int height; 49 | int format; 50 | }; 51 | //format: 1:YUV420, 2:h264 52 | int zxw_capture_init(ZXW_Capture ** capture, int width, int height, int format, int devnum) { 53 | char DevicePath[32]; 54 | sprintf(DevicePath,"/dev/video%d", devnum); 55 | LOGE("capture device path: %s", DevicePath); 56 | 57 | uint32_t pixFmt = V4L2_PIX_FMT_H264; 58 | switch(format) { 59 | case 1: pixFmt = V4L2_PIX_FMT_YUYV; break; 60 | case 2: pixFmt = V4L2_PIX_FMT_H264; break; 61 | default: pixFmt = 0; break; 62 | }; 63 | ZXW_Capture *zxw_capture = (ZXW_Capture*) malloc(sizeof(ZXW_Capture)); 64 | if (zxw_capture == NULL) { 65 | LOGE("memory error: fail to alloc ZXW_Capture"); 66 | return -1; 67 | } 68 | zxw_capture->width = width; 69 | zxw_capture->height = height; 70 | zxw_capture->format = format; 71 | 72 | 73 | V4l2Capture *v4l2cap = new V4l2Capture(DevicePath); 74 | 75 | if(!v4l2cap->ConfigureDev(width, height,pixFmt, 0)) 76 | { 77 | LOGE("Failed to config device.\r\n"); 78 | v4l2cap->UnConfigureDev(); 79 | return 0; 80 | } 81 | 82 | zxw_capture->v4l2cap = v4l2cap; 83 | 84 | *capture = zxw_capture; 85 | 86 | return 0; 87 | } 88 | 89 | int zxw_capture_deint(ZXW_Capture *capture) { 90 | if (capture == NULL) return 0; 91 | 92 | if (capture->v4l2cap != NULL ) { 93 | capture->v4l2cap->UnConfigureDev(); 94 | delete capture->v4l2cap; 95 | capture->v4l2cap = NULL; 96 | } 97 | 98 | free(capture); 99 | } 100 | 101 | int zxw_capture_getFrame(ZXW_Capture *capture, char *frame, int *size) { 102 | if (capture == NULL || capture->v4l2cap == NULL) return -1; 103 | capture->v4l2cap->CaptureFrame((uint8_t*)frame, (uint32_t*)size); 104 | return 0; 105 | } 106 | 107 | int zxw_capture_setH264Bitrate(ZXW_Capture *capture, int bitrate) { 108 | if (capture == NULL || capture->v4l2cap == NULL) return -1; 109 | return capture->v4l2cap->SetH264BitRate(bitrate); 110 | } 111 | -------------------------------------------------------------------------------- /vm_dump_test/V4l2CaptureInterface.d: -------------------------------------------------------------------------------- 1 | V4l2CaptureInterface.o: V4l2CaptureInterface.cpp V4l2Capture.hpp \ 2 | MediaSample.hpp V4l2CaptureInterface.h 3 | 4 | V4l2Capture.hpp: 5 | 6 | MediaSample.hpp: 7 | 8 | V4l2CaptureInterface.h: 9 | -------------------------------------------------------------------------------- /vm_dump_test/V4l2CaptureInterface.h: -------------------------------------------------------------------------------- 1 | #ifndef __V4l2Capture_Interface_H__ 2 | #define __V4l2Capture_Interface_H__ 3 | #ifdef __cplusplus 4 | extern "C" { 5 | #endif 6 | #define DEVICE_PATH "/dev/video2" 7 | 8 | //#define V4L2_PIX_FMT_H264 v4l2_fourcc('H', '2', '6', '4') 9 | #define V4L2_PIX_FMT_H264 0 10 | 11 | typedef struct ZXW_Capture ZXW_Capture; 12 | //format: 1:YUV420, 2:h264 13 | int zxw_capture_init(ZXW_Capture ** catpure, int width, int height, int format, int devnum); 14 | 15 | int zxw_capture_deint(ZXW_Capture *capture); 16 | 17 | int zxw_capture_getFrame(ZXW_Capture *capture, char *frame, int *size); 18 | 19 | int zxw_capture_setH264Bitrate(ZXW_Capture *capture, int bitrate); 20 | 21 | 22 | #ifdef __cplusplus 23 | } 24 | #endif 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /vm_dump_test/debugging.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2007-2009 Skype Technologies S.A. Confidential and proprietary 3 | * 4 | * All intellectual property rights, including but not limited to copyrights, 5 | * trademarks and patents, as well as know how and trade secrets contained 6 | * in, relating to, or arising from the internet telephony software of Skype 7 | * Limited (including its affiliates, "Skype"), including without limitation 8 | * this source code, Skype API and related material of such software 9 | * proprietary to Skype and/or its licensors ("IP Rights") are and shall 10 | * remain the exclusive property of Skype and/or its licensors. The recipient 11 | * hereby acknowledges and agrees that any unauthorized use of the IP Rights 12 | * is a violation of intellectual property laws. 13 | * 14 | * Skype reserves all rights and may take legal action against infringers of 15 | * IP Rights. 16 | * 17 | * The recipient agrees not to remove, obscure, make illegible or alter any 18 | * notices or indications of the IP Rights and/or Skype's rights and ownership 19 | * thereof. 20 | */ 21 | 22 | /* 23 | * Following preprocessor variables affect the behavior: 24 | * ENABLE_DEBUG - nothing will be logged if not defined 25 | * DEBUG_LONG_FORMAT - appends file, line and function name as a prefix to each log message 26 | * LOG_PREFIX - a prefix that will be added to all logging messages 27 | * LOG_MASK - mask constant. Each bit enables certain logging level. 28 | * (0x01 - ERROR, 0x02 - WARN ... 0x10 -VDBG) 29 | * For example use LOG_MASK=0x3 to enable errors and warnings only 30 | * 31 | * Note that you can add your own logging levels in each file this way: 32 | * #define MY_DEBUG1(fmt, args...) LOG(0x20, fmt, ##args) 33 | * #define MY_DEBUG2(fmt, args...) LOG(0x40, fmt, ##args) 34 | * */ 35 | 36 | #ifndef DEBUGGING_HPP 37 | #define DEBUGGING_HPP 38 | 39 | 40 | //#undef EMBEDDED_API_SERVER 41 | #ifdef EMBEDDED_API_SERVER 42 | 43 | #include "misc.hpp" 44 | #include 45 | 46 | #define __FATAL FatalError 47 | #define __DBG DbgPrintf 48 | 49 | #else 50 | 51 | #include 52 | #include 53 | #include 54 | #include 55 | #include 56 | 57 | /// Fatal error 58 | inline void __FATAL(const char *format, ...) 59 | { 60 | va_list ap; 61 | va_start(ap, format); 62 | 63 | vprintf(format, ap); 64 | 65 | abort(); 66 | } 67 | 68 | /// printf-style debug print 69 | inline void __DBG(const char *format, ...) 70 | { 71 | va_list ap; 72 | va_start(ap, format); 73 | vprintf(format, ap); 74 | } 75 | #endif // !EMBEDDED_API_SERVER 76 | 77 | #ifndef USE_TIMESTAMPS 78 | #define USE_TIMESTAMPS 0 79 | #endif 80 | 81 | #ifndef LOG_PREFIX 82 | #define LOG_PREFIX "" 83 | #endif 84 | 85 | #ifndef LOG_MASK 86 | #define LOG_MASK 0x0000000f 87 | #endif 88 | 89 | /* 90 | time_t tim=time(NULL); \ 91 | struct tm *t=localtime(&tim); \ 92 | __DBG("%02d:%02d:%02d " fmt "\n", t->tm_hour, t->tm_min, t->tm_sec, ##args); \ 93 | 94 | */ 95 | #include 96 | #define _DBG(use_timestamps, fmt, args...) \ 97 | do { \ 98 | if (use_timestamps) { \ 99 | struct timeval tv;\ 100 | gettimeofday(&tv, NULL);\ 101 | __DBG("%02d:%02d:%02d:%02d " fmt "\n", (tv.tv_sec % 14400)/ 3600, (tv.tv_sec % 3600) / 60, tv.tv_sec % 60, tv.tv_usec / 10000, ##args); \ 102 | } else {\ 103 | __DBG(fmt "\n", ##args); \ 104 | } \ 105 | } while (0) 106 | 107 | #define FATAL(fmt, args...) __FATAL(LOG_PREFIX fmt "\n", ##args) 108 | 109 | #ifdef ENABLE_DEBUG 110 | 111 | 112 | #ifdef DEBUG_LONG_FORMAT 113 | #define _LOG(use_timestamps, level, prefix, file, line, func, fmt, args...) \ 114 | if (LOG_MASK & level) { \ 115 | _DBG(use_timestamps, LOG_PREFIX prefix "%s:%d(%s): " fmt, file, line, func, ##args); \ 116 | } 117 | #else 118 | #define _LOG(use_timestamps, level, prefix, file, line, func, fmt, args...) \ 119 | if (LOG_MASK & level) { \ 120 | _DBG(use_timestamps, LOG_PREFIX prefix fmt, ##args); \ 121 | } 122 | #endif 123 | 124 | #else 125 | #define _LOG(level, fmt, args...) 126 | #endif 127 | 128 | #define ERROR(fmt, args...) _LOG(USE_TIMESTAMPS, 0x1, "ERR: ", __FILE__, __LINE__, __func__, fmt, ##args) 129 | #define WARN(fmt, args...) _LOG(USE_TIMESTAMPS, 0x2, "WRN: ", __FILE__, __LINE__, __func__, fmt, ##args) 130 | #define INFO(fmt, args...) _LOG(USE_TIMESTAMPS, 0x4, "INF: ", __FILE__, __LINE__, __func__, fmt, ##args) 131 | #define DBG(fmt, args...) _LOG(USE_TIMESTAMPS, 0x8, "DBG: ", __FILE__, __LINE__, __func__, fmt, ##args) 132 | #define VDBG(fmt, args...) _LOG(USE_TIMESTAMPS, 0x10, "VDBG: ", __FILE__, __LINE__, __func__, fmt, ##args) 133 | #define LOG(level, fmt, args...) _LOG(USE_TIMESTAMPS, level, "", __FILE__, __LINE__, __func__, fmt, ##args) 134 | 135 | /// Function logger, used through FUNCLOG macro 136 | struct FuncLog 137 | { 138 | inline FuncLog (const char *func_ ) : 139 | func(func_), 140 | prefix("FLOG:"), 141 | logMask(LOG_MASK), 142 | logLevel(0x8), 143 | useTimestamps(USE_TIMESTAMPS) 144 | { 145 | if (logMask & logLevel) 146 | _DBG(useTimestamps, "%s%s", prefix, func); 147 | } 148 | inline FuncLog (const char *func_, const char *prefix_, unsigned int useTimestamps_, unsigned int logMask_, unsigned int logLevel_) : 149 | func(func_), 150 | prefix(prefix_), 151 | logMask(logMask_), 152 | logLevel(logLevel_), 153 | useTimestamps(useTimestamps_) 154 | { 155 | if (logMask & logLevel) 156 | _DBG(useTimestamps, "%s%s", prefix, func); 157 | } 158 | inline ~FuncLog() { 159 | if (logMask & logLevel) 160 | _DBG(useTimestamps, "%s%s --end", prefix, func); 161 | } 162 | private: 163 | const char *func, *prefix; 164 | unsigned int logMask, logLevel, useTimestamps; 165 | }; 166 | 167 | 168 | #define FUNCLOG FuncLog __l(__func__, "FLOG:", USE_TIMESTAMPS, LOG_MASK, 0x08); 169 | 170 | #endif 171 | 172 | -------------------------------------------------------------------------------- /vm_dump_test/libzxwcapture.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icefreedom/v4l2virtualdevice_android/2d8a7659789435fd8bc7f4e3ca073d0bb34d1424/vm_dump_test/libzxwcapture.a -------------------------------------------------------------------------------- /vm_dump_test/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | //#include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include "V4l2Capture.hpp" 19 | 20 | #define DEVICE_PATH "/dev/video0" 21 | 22 | //#ifndef V4L2_PIX_FMT_H264 23 | //#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0) 24 | //#define V4L2_PIX_FMT_H264 v4l2_fourcc('H', '2', '6', '4') 25 | //#else 26 | #define V4L2_PIX_FMT_H264 0 //remake for new kernel 27 | //#endif 28 | //#endif 29 | 30 | #define ST_YUY2 41 31 | #define ST_H264 43 32 | 33 | #define YUY2_WIDTH 640 34 | #define YUY2_HEIGHT 480 35 | #define H264_WIDTH 640 36 | #define H264_HEIGHT 480 37 | 38 | #define REC_FRAMES 15*60 //10 sec 39 | #define BITRATE 256 //2500KBPS 40 | #define FPS 10 //30 FPS 41 | 42 | using namespace std; 43 | 44 | bool compute_again = true; 45 | struct timeval start_time, current_time; 46 | int yuv_count = 0; 47 | bool exit_flag = true; 48 | 49 | static int my_count = 0; 50 | 51 | 52 | int main(int argc,char** argv) 53 | { 54 | //thread_param_set(); 55 | bool exit = false; 56 | char DevicePath[32]; 57 | int interval; 58 | 59 | if(argc>1) 60 | { 61 | sprintf(DevicePath,"%s",argv[1]); 62 | } 63 | else 64 | { 65 | sprintf(DevicePath,DEVICE_PATH,argv[1]); 66 | } 67 | printf("DevicePath = %s\n", DevicePath); 68 | 69 | V4l2Capture *v4l2cap = new V4l2Capture(DevicePath); 70 | 71 | if(!v4l2cap->ConfigureDev(H264_WIDTH,H264_HEIGHT,V4L2_PIX_FMT_YUYV, 0)) 72 | { 73 | printf("Failed to config device.\r\n"); 74 | v4l2cap->UnConfigureDev(); 75 | return 0; 76 | } 77 | 78 | MediaSample sample; 79 | sample.AllocBuffer(H264_WIDTH*H264_HEIGHT*2); 80 | 81 | FILE *fd_h264 = NULL; 82 | //FILE *fd_yuy2 = NULL; 83 | fd_h264 = fopen("yuy2_dump.bin","w+b"); 84 | //fd_yuy2 = fopen("yuy2_dump.bin","w+b"); 85 | 86 | exit_flag = false; 87 | struct timeval start; 88 | struct timeval end; 89 | gettimeofday(&start, NULL); 90 | //for(int n =0; nCaptureFrame(sample); 95 | 96 | if(frame_size>0) 97 | { 98 | //fwrite(sample.GetBuffer(), frame_size, 1, fd_h264); 99 | //fwrite( media_sample.yuy2, media_sample.yuy2_size, 1, fd_yuy2); 100 | } 101 | else 102 | { 103 | printf("frame size = 0"); 104 | } 105 | 106 | if (n % 50 == 0) { 107 | if (n == 0) { 108 | gettimeofday(&start, NULL); 109 | } else { 110 | gettimeofday(&end, NULL); 111 | long secs = 1000000 * (end.tv_sec - start.tv_sec) + end.tv_usec - start.tv_usec; 112 | secs /= 1000000; 113 | printf("fps = %f\n", 50.0 / secs); 114 | } 115 | gettimeofday(&start, NULL); 116 | } 117 | ++n; 118 | 119 | } 120 | // printf("frame %d\r\n",n); 121 | 122 | printf("capture over\n"); 123 | //if(fd_yuy2) 124 | // fclose(fd_yuy2); 125 | if(fd_h264) 126 | fclose(fd_h264); 127 | 128 | //close uvc camera 129 | v4l2cap->UnConfigureDev(); 130 | delete v4l2cap; 131 | 132 | exit_flag = true; 133 | 134 | return 0; 135 | } 136 | -------------------------------------------------------------------------------- /vm_dump_test/main.d: -------------------------------------------------------------------------------- 1 | main.o: main.cpp V4l2Capture.hpp MediaSample.hpp 2 | 3 | V4l2Capture.hpp: 4 | 5 | MediaSample.hpp: 6 | -------------------------------------------------------------------------------- /vm_dump_test/uvcvideo.h: -------------------------------------------------------------------------------- 1 | #ifndef __LINUX_UVCVIDEO_H_ 2 | #define __LINUX_UVCVIDEO_H_ 3 | 4 | #include 5 | #include 6 | 7 | /* 8 | * Dynamic controls 9 | */ 10 | 11 | /* Data types for UVC control data */ 12 | #define UVC_CTRL_DATA_TYPE_RAW 0 13 | #define UVC_CTRL_DATA_TYPE_SIGNED 1 14 | #define UVC_CTRL_DATA_TYPE_UNSIGNED 2 15 | #define UVC_CTRL_DATA_TYPE_BOOLEAN 3 16 | #define UVC_CTRL_DATA_TYPE_ENUM 4 17 | #define UVC_CTRL_DATA_TYPE_BITMASK 5 18 | 19 | /* Control flags */ 20 | #define UVC_CTRL_FLAG_SET_CUR (1 << 0) 21 | #define UVC_CTRL_FLAG_GET_CUR (1 << 1) 22 | #define UVC_CTRL_FLAG_GET_MIN (1 << 2) 23 | #define UVC_CTRL_FLAG_GET_MAX (1 << 3) 24 | #define UVC_CTRL_FLAG_GET_RES (1 << 4) 25 | #define UVC_CTRL_FLAG_GET_DEF (1 << 5) 26 | /* Control should be saved at suspend and restored at resume. */ 27 | #define UVC_CTRL_FLAG_RESTORE (1 << 6) 28 | /* Control can be updated by the camera. */ 29 | #define UVC_CTRL_FLAG_AUTO_UPDATE (1 << 7) 30 | 31 | #define UVC_CTRL_FLAG_GET_RANGE \ 32 | (UVC_CTRL_FLAG_GET_CUR | UVC_CTRL_FLAG_GET_MIN | \ 33 | UVC_CTRL_FLAG_GET_MAX | UVC_CTRL_FLAG_GET_RES | \ 34 | UVC_CTRL_FLAG_GET_DEF) 35 | 36 | struct uvc_menu_info { 37 | __u32 value; 38 | __u8 name[32]; 39 | }; 40 | 41 | struct uvc_xu_control_mapping { 42 | __u32 id; 43 | __u8 name[32]; 44 | __u8 entity[16]; 45 | __u8 selector; 46 | 47 | __u8 size; 48 | __u8 offset; 49 | __u32 v4l2_type; 50 | __u32 data_type; 51 | 52 | struct uvc_menu_info *menu_info; 53 | __u32 menu_count; 54 | 55 | __u32 reserved[4]; 56 | }; 57 | 58 | struct uvc_xu_control_query { 59 | __u8 unit; 60 | __u8 selector; 61 | __u8 query; /* Video Class-Specific Request Code, */ 62 | /* defined in linux/usb/video.h A.8. */ 63 | __u16 size; 64 | __u8 *data; 65 | }; 66 | 67 | #define UVCIOC_CTRL_MAP _IOWR('u', 0x20, struct uvc_xu_control_mapping) 68 | #define UVCIOC_CTRL_QUERY _IOWR('u', 0x21, struct uvc_xu_control_query) 69 | 70 | #endif 71 | -------------------------------------------------------------------------------- /vm_dump_test/vm.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include 18 | #include 19 | 20 | //#include "vmioctrl.h" 21 | 22 | #define CLEAR(x) memset (&(x), 0, sizeof (x)) 23 | static int frame_count = 1000; 24 | struct buffer { 25 | void * start; 26 | size_t length; 27 | }; 28 | 29 | static char * dev_name = "/dev/video1";//default device name 30 | static int fd = -1; 31 | struct buffer * buffers = NULL; 32 | static unsigned int n_buffers = 0; 33 | const static short img_width = 640; 34 | const static short img_height = 480; 35 | static int *file_fd = -1; 36 | static unsigned char *file_name; 37 | ////////////////////////////////////////////////////// 38 | //Get frame 39 | ////////////////////////////////////////////////////// 40 | static int read_frame (void) 41 | { 42 | struct v4l2_buffer buf; 43 | unsigned int i; 44 | 45 | CLEAR (buf); 46 | buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 47 | buf.memory = V4L2_MEMORY_MMAP; 48 | 49 | ioctl (fd, VIDIOC_DQBUF, &buf); //Get frame from buffer 50 | 51 | 52 | 53 | write(file_fd, buffers[buf.index].start,buf.bytesused); //Dump video to a file 54 | ioctl (fd, VIDIOC_QBUF, &buf); //re-queue buffer 55 | 56 | return 1; 57 | } 58 | 59 | int main (int argc,char ** argv) 60 | { 61 | struct v4l2_capability cap; 62 | struct v4l2_format fmt; 63 | unsigned int i; 64 | enum v4l2_buf_type type; 65 | struct vdIn *m_vd; 66 | 67 | 68 | 69 | file_fd = open("test-mmap0.es", O_CREAT|O_WRONLY|O_NONBLOCK, S_IRWXU|S_IRWXG|S_IRWXO); 70 | fd = open (dev_name, O_RDWR /* required */ | O_NONBLOCK, 0); 71 | 72 | 73 | ioctl (fd, VIDIOC_QUERYCAP, &cap);//get device capability 74 | 75 | CLEAR (fmt); 76 | fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 77 | fmt.fmt.pix.width = img_width; 78 | fmt.fmt.pix.height = img_height; 79 | fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_H264;//V4L2_PIX_FMT_YUYV;// 80 | fmt.fmt.pix.field = V4L2_FIELD_ANY; 81 | ioctl (fd, VIDIOC_S_FMT, &fmt); //set video format. 82 | 83 | 84 | 85 | struct v4l2_requestbuffers req; 86 | CLEAR (req); 87 | req.count = 4; 88 | req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 89 | req.memory = V4L2_MEMORY_MMAP; 90 | 91 | ioctl (fd, VIDIOC_REQBUFS, &req); //request buffers from V4L2 92 | 93 | if (req.count < 2) 94 | printf("Insufficient buffer memory\n"); 95 | 96 | buffers = calloc (req.count, sizeof (*buffers)); //alloca buffers 97 | 98 | for (n_buffers = 0; n_buffers < req.count; ++n_buffers) 99 | { 100 | struct v4l2_buffer buf; 101 | CLEAR (buf); 102 | buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 103 | buf.memory = V4L2_MEMORY_MMAP; 104 | buf.index = n_buffers; 105 | 106 | if (-1 == ioctl (fd, VIDIOC_QUERYBUF, &buf)) //ӳ 107 | printf ("VIDIOC_QUERYBUF error\n"); 108 | 109 | buffers[n_buffers].length = buf.length; 110 | buffers[n_buffers].start = 111 | mmap (NULL /* start anywhere */, //mmap memory 112 | buf.length, 113 | PROT_READ | PROT_WRITE /* required */, 114 | MAP_SHARED /* recommended */, 115 | fd, buf.m.offset); 116 | 117 | if (MAP_FAILED == buffers[n_buffers].start) 118 | printf ("mmap failed\n"); 119 | } 120 | 121 | for (i = 0; i < n_buffers; ++i) 122 | { 123 | struct v4l2_buffer buf; 124 | CLEAR (buf); 125 | 126 | buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 127 | buf.memory = V4L2_MEMORY_MMAP; 128 | buf.index = i; 129 | 130 | if (-1 == ioctl (fd, VIDIOC_QBUF, &buf)) 131 | printf ("VIDIOC_QBUF failed\n"); 132 | } 133 | 134 | type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 135 | 136 | if (-1 == ioctl (fd, VIDIOC_STREAMON, &type)) 137 | printf ("VIDIOC_STREAMON failed\n"); 138 | fd_set fds; 139 | for (int i = 0; i < frame_count; i++) 140 | { 141 | 142 | struct timeval tv; 143 | int r; 144 | 145 | FD_ZERO (&fds); 146 | FD_SET (fd, &fds); 147 | 148 | /* Timeout. */ 149 | tv.tv_sec = 1; 150 | tv.tv_usec = 0; 151 | 152 | r = select (fd + 1, &fds, NULL, NULL, &tv); 153 | 154 | if (read_frame ()) 155 | printf("R\n"); 156 | //break; 157 | } 158 | 159 | unmap: 160 | for (i = 0; i < n_buffers; ++i) 161 | if (-1 == munmap (buffers[i].start, buffers[i].length)) 162 | printf ("munmap error"); 163 | close (fd); 164 | close (file_fd); 165 | free(buffers); 166 | exit (EXIT_SUCCESS); 167 | return 0; 168 | } 169 | -------------------------------------------------------------------------------- /vm_dump_test/yuy2_dump.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icefreedom/v4l2virtualdevice_android/2d8a7659789435fd8bc7f4e3ca073d0bb34d1424/vm_dump_test/yuy2_dump.bin --------------------------------------------------------------------------------