diff --git a/loopback.cpp b/loopback.cpp
index 2b99d661ca749e02288f25ba0e4309213228c44b..18a1cf352feaa7046715a34531d8d01c7cae0969 100644 (file)
--- a/loopback.cpp
+++ b/loopback.cpp
int height;
char dev_name[9];
char name[4];
+ int buf_current;
char *buf_start;
+ char *buf_start2;
unsigned int buf_length;
struct fb_fix_screeninfo fixinfo;
struct omapfb_display_info di;
struct omapfb_mem_info mi;
struct omapfb_plane_info pi;
+ struct omapfb_caps caps;
+
+ enum omapfb_update_mode update_mode;
} fb1_device, fb2_device;
return 0;
}
+/*
+ * Queue V4L2 buffer
+ */
+static int v4l2_queue_buffer(struct v4l2_device_info *device)
+{
+ int ret;
+ fd_set fds;
+ struct timeval tv;
+
+ FD_ZERO(&fds);
+ FD_SET(device->fd, &fds);
+
+ /* Timeout. */
+ tv.tv_sec = 10;
+ tv.tv_usec = 0;
+
+ ret = select(device->fd + 1, &fds, NULL, NULL, &tv);
+
+ if (-1 == ret) {
+ if (EINTR == errno) {
+ perror( "select\n");
+ return -1;
+ }
+ }
+
+ if (0 == ret) {
+ perror( "select timeout\n");
+ return -1;
+ }
+
+ /* Queue buffer for the v4l2 capture device */
+ ret = ioctl(device->fd, VIDIOC_QBUF,
+ &device->buf);
+ if (ret < 0) {
+ perror("VIDIOC_QBUF");
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * DeQueue V4L2 buffer
+ */
+static int v4l2_dequeue_buffer(struct v4l2_device_info *device)
+{
+ int ret;
+ fd_set fds;
+ struct timeval tv;
+
+ FD_ZERO(&fds);
+ FD_SET(device->fd, &fds);
+
+ /* Timeout. */
+ tv.tv_sec = 10;
+ tv.tv_usec = 0;
+
+ ret = select(device->fd + 1, &fds, NULL, NULL, &tv);
+
+ if (-1 == ret) {
+ if (EINTR == errno) {
+ perror( "select\n");
+ return -1;
+ }
+ }
+
+ if (0 == ret) {
+ perror( "select timeout\n");
+ return -1;
+ }
+
+ /* Dequeue buffer for the v4l2 capture device */
+ ret = ioctl(device->fd, VIDIOC_DQBUF,
+ &device->buf);
+ if (ret < 0) {
+ perror("VIDIOC_DQBUF");
+ return -1;
+ }
+
+ return 0;
+}
+
/*
* Fbdev device init
*/
exit(0);
}
- printf("%s resolution: %dx%d\n",device->name, device->di.xres, device->di.yres);
-
/* Now the memory for the fb device needs to be set up */
if (ioctl(device->fd, OMAPFB_QUERY_PLANE, &device->pi)) {
}
}
- printf("Display Screen Properties:\n");
+ printf("\nDisplay Screen Properties:\n");
printf("%s bpp: %d\n",device->name, device->varinfo.bits_per_pixel);
printf("%s di resolution: %dx%d\n",device->name,
device->di.xres, device->di.yres);
status.display_xres = device->di.xres;
status.display_yres = device->di.yres;
+ if (device->di.xres < 640) {
+ device->width = 640;
+ device->height = 480;
+ }
+
/* Set the input resolution of the video framebuffer to be the size
* of the camera image. Later, the output size will be matched to
* the display to allow for up/down scaling */
device->varinfo.xres = device->width;
device->varinfo.yres = device->height;
device->varinfo.xres_virtual = device->width;
- device->varinfo.yres_virtual = device->height;
+ device->varinfo.yres_virtual = 2 * device->height;
device->varinfo.bits_per_pixel = 16;
device->varinfo.nonstd = OMAPFB_COLOR_YUY422;
device->pi.out_height = device->di.yres;
device->pi.enabled = 1;
+ /* Get device capabilities */
+ ioctl(device->fd,OMAPFB_GET_CAPS, &device->caps);
+
+ printf("Checking for manual update capability...\n");
+ if (device->caps.ctrl & OMAPFB_CAPS_MANUAL_UPDATE)
+ printf("Manual update supported\n");
+
+ ioctl(device->fd,OMAPFB_GET_UPDATE_MODE, &device->update_mode);
+ printf("OMAPFB_GET_UPDATE_MODE: %d\n", device->update_mode);
+
if (ioctl(device->fd, OMAPFB_SETUP_PLANE, &device->pi)) {
printf("OMAPFB_SETUP_PLANE error for: %s\n", device->name);
exit(0);
device->fixinfo.line_length);
/* Mmap the driver buffers in application space so that application
- * can write on to them */
+ * can write on to them. Buffers need to be 2x for double buffering
+ * to eliminate tearing
+ */
device->buf_length = device->fixinfo.line_length * device->varinfo.yres_virtual;
device->buf_start = (char *)mmap (0, device->buf_length,
(PROT_READ|PROT_WRITE), MAP_SHARED, device->fd, 0);
+ device->buf_start2 = device->buf_start + device->buf_length/2;
+
+ printf("1st buffer addr: %x\n", (unsigned int)device->buf_start);
+ printf("2nd buffer addr: %x\n", (unsigned int)device->buf_start2);
if (device->buf_start == MAP_FAILED) {
printf("MMap failed for %s\n", device->name);
}
/*
- * Set up the DSS for PiP plane
+ * Set up the DSS for blending of video and graphics planes
*/
-static int fbdev_init_pip(void)
+static int fbdev_init_dss(void)
{
FILE *f;
/*
* Fbdev enable pip layer
*/
-static int fbdev_enable_pip(void)
+int fbdev_enable_pip(void)
{
fb2_device.pi.enabled = 1;
if (ioctl(fb2_device.fd, OMAPFB_SETUP_PLANE, &fb2_device.pi)) {
/*
* Fbdev disable pip layer
*/
-static int fbdev_disable_pip(void)
+int fbdev_disable_pip(void)
{
fb2_device.pi.enabled = 0;
if (ioctl(fb2_device.fd, OMAPFB_SETUP_PLANE, &fb2_device.pi)) {
*/
static int display_frame(struct v4l2_device_info *v4l2_device, struct fbdev_device_info *fbdev_device)
{
- int ret, fb_size = fbdev_device->fixinfo.line_length*fbdev_device->varinfo.yres;
- fd_set fds;
- struct timeval tv;
-
- FD_ZERO(&fds);
- FD_SET(v4l2_device->fd, &fds);
-
- /* Timeout. */
- tv.tv_sec = 10;
- tv.tv_usec = 0;
-
- ret = select(v4l2_device->fd + 1, &fds, NULL, NULL, &tv);
-
- if (-1 == ret) {
- if (EINTR == errno) {
- perror( "select\n");
- return -1;
+ int fb_size = fbdev_device->fixinfo.line_length*fbdev_device->varinfo.yres;
+
+ /* Request a capture buffer from the driver that can be copied to framebuffer */
+ v4l2_dequeue_buffer(v4l2_device);
+
+ /* Copy the new camera frame into the buffer that is not currently displayed */
+ if (fbdev_device->buf_current == 0)
+ {
+ /* Copy the contents of the v4l2 capture buffer to framebuffer */
+ memcpy(fbdev_device->buf_start2,
+ v4l2_device->buffers[v4l2_device->buf.index].start,
+ fb_size);
+
+ /* After the buffer copy is complete, tell the DSS to display the new data */
+ fbdev_device->varinfo.yoffset = 600;
+ ioctl(fbdev_device->fd,FBIOPAN_DISPLAY, fbdev_device->varinfo);
+ if (ioctl(fbdev_device->fd, FBIOPUT_VSCREENINFO, &fbdev_device->varinfo) < 0) {
+ printf("Error setting variable information for: %s\n", fbdev_device->name);
+ exit(0);
}
+ fbdev_device->buf_current=1;
}
-
- if (0 == ret) {
- perror( "select timeout\n");
- return -1;
+ else {
+ /* Copy the contents of the v4l2 capture buffer to framebuffer */
+ memcpy(fbdev_device->buf_start,
+ v4l2_device->buffers[v4l2_device->buf.index].start,
+ fb_size);
+
+ /* After the buffer copy is complete, tell the DSS to display the new data */
+ fbdev_device->varinfo.yoffset = 0;
+ ioctl(fbdev_device->fd,FBIOPAN_DISPLAY, fbdev_device->varinfo);
+ if (ioctl(fbdev_device->fd, FBIOPUT_VSCREENINFO, &fbdev_device->varinfo) < 0) {
+ printf("Error setting variable information for: %s\n", fbdev_device->name);
+ exit(0);
+ }
+ fbdev_device->buf_current=0;
}
- /* Dequeue buffer for the v4l2 capture device */
- ret = ioctl(v4l2_device->fd, VIDIOC_DQBUF,
- &v4l2_device->buf);
- if (ret < 0) {
- perror("VIDIOC_DQBUF");
- return -1;
- }
- /* Wait for VSYNC */
- ioctl(fbdev_device->fd, OMAPFB_WAITFORGO);
+ /* Give the buffer back to the driver so it can be filled again */
+ v4l2_queue_buffer(v4l2_device);
- /* Copy the contents of the v4l2 capture buffer to framebuffer */
- memcpy(fbdev_device->buf_start,
- v4l2_device->buffers[v4l2_device->buf.index].start,
- fb_size);
+ return 0;
+}
- /* Queue buffer for the v4l2 capture device */
- ret = ioctl(v4l2_device->fd, VIDIOC_QBUF,
- &v4l2_device->buf);
- if (ret < 0) {
- perror("VIDIOC_QBUF");
- return -1;
- }
+/*
+ * Capture v4l2 frame and save to jpeg
+ */
+static int capture_frame(struct v4l2_device_info *v4l2_device)
+{
+ /* Request a capture buffer from the driver that can be copied to framebuffer */
+ v4l2_dequeue_buffer(v4l2_device);
+
+ jpegWrite((unsigned char *)v4l2_device->buffers[cap0_device.buf.index].start,
+ status.num_jpeg, v4l2_device->width, v4l2_device->height);
+
+ /* Give the buffer back to the driver so it can be filled again */
+ v4l2_queue_buffer(v4l2_device);
return 0;
}
strcpy(fb1_device.name,"fb1");
fb1_device.width=800;
fb1_device.height=600;
+ fb1_device.buf_current=0;
/* PiP camera display */
strcpy(fb2_device.dev_name,"/dev/fb2");
strcpy(fb2_device.name,"fb2");
fb2_device.width=800;
fb2_device.height=600;
+ fb2_device.buf_current=0;
/* Main camera */
cap0_device.memory_mode = V4L2_MEMORY_MMAP;
void exit_devices(void)
{
+ fbdev_exit_device(&fb1_device);
+ fbdev_exit_device(&fb2_device);
+
v4l2_exit_device(&cap0_device);
if (status.num_cams==2) {
v4l2_exit_device(&cap1_device);
}
-
- fbdev_exit_device(&fb1_device);
- fbdev_exit_device(&fb2_device);
}
void end_streaming(void)
/* Declare properties for video and capture devices */
default_parameters();
+ /* Initialize the fbdev display devices */
+ if (fbdev_init_device(&fb1_device)) goto Error;
+ if (fbdev_init_device(&fb2_device)) goto Error;
+
+ /* Check to see if the display resolution is very small. If so, the
+ * camera capture resolution needs to be lowered so that the scaling
+ * limits of the DSS are not reached */
+ if (fb1_device.di.xres < 640) {
+ /* Set capture 0 device resolution */
+ cap0_device.width = 640;
+ cap0_device.height = 480;
+
+ /* Set capture 1 device resolution */
+ cap1_device.width = 640;
+ cap1_device.height = 480;
+ }
+
/* Initialize the v4l2 capture devices */
if (v4l2_init_device(&cap0_device) < 0) goto Error;
if (v4l2_init_device(&cap1_device) < 0) {
if (v4l2_stream_on(&cap1_device) < 0) goto Error;
}
- /* Initialize the fbdev display devices */
- if (fbdev_init_device(&fb1_device)) goto Error;
- if (fbdev_init_device(&fb2_device)) goto Error;
+ /* Configure the DSS to blend video and graphics layers */
+ if (fbdev_init_dss() < 0 ) goto Error;
if (status.pip==false)
fbdev_disable_pip();
- else {
- /* Set the scalar for PiP */
- if (fbdev_init_pip() < 0 ) goto Error;
- }
+ else
+ fbdev_enable_pip();
return 0;
*/
void process_frame(void) {
- /* Display main camera */
+ /* Display the main camera */
if (status.main_cam==0)
display_frame(&cap0_device, &fb1_device);
else
display_frame(&cap1_device, &fb1_device);
- // Display PiP if enabled
+ /* Display PiP if enabled */
if (status.pip==true) {
- fbdev_enable_pip();
-
if (status.main_cam==0)
display_frame(&cap1_device, &fb2_device);
else
display_frame(&cap0_device, &fb2_device);
}
- else
- fbdev_disable_pip();
-
- // Save jpeg image if triggered
+ /* Save jpeg image if triggered */
if (status.jpeg==true) {
if (status.main_cam==0) {
- jpegWrite((unsigned char *)cap0_device.buffers[cap0_device.buf.index].start,
- status.num_jpeg);
-
+ capture_frame(&cap0_device);
}
else {
- jpegWrite((unsigned char *)cap1_device.buffers[cap1_device.buf.index].start,
- status.num_jpeg);
-
+ capture_frame(&cap1_device);
}
status.jpeg=false;