diff --git a/src/zm_local_camera.cpp b/src/zm_local_camera.cpp index 8f38b4d99..795aaab7c 100644 --- a/src/zm_local_camera.cpp +++ b/src/zm_local_camera.cpp @@ -259,12 +259,12 @@ LocalCamera::LocalCamera( v4l_multi_buffer = p_v4l_multi_buffer; v4l_captures_per_frame = p_v4l_captures_per_frame; - if ( capture ) { - if ( device_prime ) { + if (capture) { + if (device_prime) { Debug(2, "V4L support enabled, using V4L%d api", v4l_version); } - if ( (!last_camera) || (channel != last_camera->channel) ) { + if ((!last_camera) || (channel != last_camera->channel)) { // We are the first, or only, input that uses this channel channel_prime = true; channel_index = channel_count++; @@ -278,10 +278,10 @@ LocalCamera::LocalCamera( /* The V4L1 API doesn't care about endianness, we need to check the endianness of the machine */ uint32_t checkval = 0xAABBCCDD; - if ( *(unsigned char*)&checkval == 0xDD ) { + if (*(unsigned char*)&checkval == 0xDD) { BigEndian = 0; Debug(2, "little-endian processor detected"); - } else if ( *(unsigned char*)&checkval == 0xAA ) { + } else if (*(unsigned char*)&checkval == 0xAA) { BigEndian = 1; Debug(2, "Big-endian processor detected"); } else { @@ -289,15 +289,15 @@ LocalCamera::LocalCamera( BigEndian = 0; } - if ( v4l_version == 2 && palette == 0 ) { + if (v4l_version == 2 && palette == 0) { /* Use automatic format selection */ Debug(2,"Using automatic format selection"); palette = AutoSelectFormat(colours); - if ( palette == 0 ) { + if (palette == 0) { Error("Automatic format selection failed. Falling back to YUYV"); palette = V4L2_PIX_FMT_YUYV; } else { - if ( capture ) { + if (capture) { Info("Selected capture palette: %s (0x%02hhx%02hhx%02hhx%02hhx)", palette_desc, static_cast((palette >> 24) & 0xff), @@ -328,130 +328,127 @@ LocalCamera::LocalCamera( imagePixFormat = AV_PIX_FMT_NONE; } - /* V4L2 format matching */ - if ( v4l_version == 2 ) { - /* Try to find a match for the selected palette and target colourspace */ + /* Try to find a match for the selected palette and target colourspace */ - /* RGB32 palette and 32bit target colourspace */ - if ( palette == V4L2_PIX_FMT_RGB32 && colours == ZM_COLOUR_RGB32 ) { - conversion_type = 0; - subpixelorder = ZM_SUBPIX_ORDER_ARGB; + /* RGB32 palette and 32bit target colourspace */ + if (palette == V4L2_PIX_FMT_RGB32 && colours == ZM_COLOUR_RGB32) { + conversion_type = 0; + subpixelorder = ZM_SUBPIX_ORDER_ARGB; - /* BGR32 palette and 32bit target colourspace */ - } else if ( palette == V4L2_PIX_FMT_BGR32 && colours == ZM_COLOUR_RGB32 ) { - conversion_type = 0; - subpixelorder = ZM_SUBPIX_ORDER_BGRA; + /* BGR32 palette and 32bit target colourspace */ + } else if (palette == V4L2_PIX_FMT_BGR32 && colours == ZM_COLOUR_RGB32) { + conversion_type = 0; + subpixelorder = ZM_SUBPIX_ORDER_BGRA; - /* RGB24 palette and 24bit target colourspace */ - } else if ( palette == V4L2_PIX_FMT_RGB24 && colours == ZM_COLOUR_RGB24 ) { - conversion_type = 0; - conversion_type = 0; - subpixelorder = ZM_SUBPIX_ORDER_BGR; + /* RGB24 palette and 24bit target colourspace */ + } else if (palette == V4L2_PIX_FMT_RGB24 && colours == ZM_COLOUR_RGB24) { + conversion_type = 0; + conversion_type = 0; + subpixelorder = ZM_SUBPIX_ORDER_BGR; - /* Grayscale palette and grayscale target colourspace */ - } else if ( palette == V4L2_PIX_FMT_GREY && colours == ZM_COLOUR_GRAY8 ) { - conversion_type = 0; + /* Grayscale palette and grayscale target colourspace */ + } else if (palette == V4L2_PIX_FMT_GREY && colours == ZM_COLOUR_GRAY8) { + conversion_type = 0; + subpixelorder = ZM_SUBPIX_ORDER_NONE; + /* Unable to find a solution for the selected palette and target colourspace. Conversion required. Notify the user of performance penalty */ + } else { + if (capture) { + Info( + "No direct match for the selected palette (%d) and target colorspace (%02u). Format conversion is required, performance penalty expected", + capturePixFormat, + colours); + } + /* Try using swscale for the conversion */ + conversion_type = 1; + Debug(2, "Using swscale for image conversion"); + if (colours == ZM_COLOUR_RGB32) { + subpixelorder = ZM_SUBPIX_ORDER_RGBA; + imagePixFormat = AV_PIX_FMT_RGBA; + } else if (colours == ZM_COLOUR_RGB24) { + subpixelorder = ZM_SUBPIX_ORDER_RGB; + imagePixFormat = AV_PIX_FMT_RGB24; + } else if (colours == ZM_COLOUR_GRAY8) { subpixelorder = ZM_SUBPIX_ORDER_NONE; - /* Unable to find a solution for the selected palette and target colourspace. Conversion required. Notify the user of performance penalty */ + imagePixFormat = AV_PIX_FMT_GRAY8; } else { - if ( capture ) { - Info( - "No direct match for the selected palette (%d) and target colorspace (%02u). Format conversion is required, performance penalty expected", - capturePixFormat, - colours); + Panic("Unexpected colours: %u",colours); + } + if (capture) { + if (!sws_isSupportedInput(capturePixFormat)) { + Error("swscale does not support the used capture format: %d", capturePixFormat); + conversion_type = 2; /* Try ZM format conversions */ } - /* Try using swscale for the conversion */ - conversion_type = 1; - Debug(2, "Using swscale for image conversion"); - if ( colours == ZM_COLOUR_RGB32 ) { - subpixelorder = ZM_SUBPIX_ORDER_RGBA; - imagePixFormat = AV_PIX_FMT_RGBA; - } else if ( colours == ZM_COLOUR_RGB24 ) { - subpixelorder = ZM_SUBPIX_ORDER_RGB; - imagePixFormat = AV_PIX_FMT_RGB24; - } else if ( colours == ZM_COLOUR_GRAY8 ) { + if (!sws_isSupportedOutput(imagePixFormat)) { + Error("swscale does not support the target format: 0x%d", imagePixFormat); + conversion_type = 2; /* Try ZM format conversions */ + } + } + /* Our YUYV->Grayscale conversion is a lot faster than swscale's */ + if (colours == ZM_COLOUR_GRAY8 && palette == V4L2_PIX_FMT_YUYV) { + conversion_type = 2; + } + + /* JPEG */ + if (palette == V4L2_PIX_FMT_JPEG || palette == V4L2_PIX_FMT_MJPEG) { + Debug(2,"Using JPEG image decoding"); + conversion_type = 3; + } + + if (conversion_type == 2) { + Debug(2,"Using ZM for image conversion"); + if ( palette == V4L2_PIX_FMT_RGB32 && colours == ZM_COLOUR_GRAY8 ) { + conversion_fptr = &std_convert_argb_gray8; subpixelorder = ZM_SUBPIX_ORDER_NONE; - imagePixFormat = AV_PIX_FMT_GRAY8; - } else { - Panic("Unexpected colours: %u",colours); - } - if ( capture ) { - if ( !sws_isSupportedInput(capturePixFormat) ) { - Error("swscale does not support the used capture format: %d", capturePixFormat); - conversion_type = 2; /* Try ZM format conversions */ - } - if ( !sws_isSupportedOutput(imagePixFormat) ) { - Error("swscale does not support the target format: 0x%d", imagePixFormat); - conversion_type = 2; /* Try ZM format conversions */ - } - } - /* Our YUYV->Grayscale conversion is a lot faster than swscale's */ - if ( colours == ZM_COLOUR_GRAY8 && palette == V4L2_PIX_FMT_YUYV ) { - conversion_type = 2; - } - - /* JPEG */ - if ( palette == V4L2_PIX_FMT_JPEG || palette == V4L2_PIX_FMT_MJPEG ) { - Debug(2,"Using JPEG image decoding"); - conversion_type = 3; - } - - if ( conversion_type == 2 ) { - Debug(2,"Using ZM for image conversion"); - if ( palette == V4L2_PIX_FMT_RGB32 && colours == ZM_COLOUR_GRAY8 ) { - conversion_fptr = &std_convert_argb_gray8; - subpixelorder = ZM_SUBPIX_ORDER_NONE; - } else if ( palette == V4L2_PIX_FMT_BGR32 && colours == ZM_COLOUR_GRAY8 ) { - conversion_fptr = &std_convert_bgra_gray8; - subpixelorder = ZM_SUBPIX_ORDER_NONE; - } else if ( palette == V4L2_PIX_FMT_YUYV && colours == ZM_COLOUR_GRAY8 ) { - /* Fast YUYV->Grayscale conversion by extracting the Y channel */ - if ( config.cpu_extensions && sse_version >= 35 ) { - conversion_fptr = &ssse3_convert_yuyv_gray8; - Debug(2,"Using SSSE3 YUYV->grayscale fast conversion"); - } else { - conversion_fptr = &std_convert_yuyv_gray8; - Debug(2,"Using standard YUYV->grayscale fast conversion"); - } - subpixelorder = ZM_SUBPIX_ORDER_NONE; - } else if ( palette == V4L2_PIX_FMT_YUYV && colours == ZM_COLOUR_RGB24 ) { - conversion_fptr = &zm_convert_yuyv_rgb; - subpixelorder = ZM_SUBPIX_ORDER_RGB; - } else if ( palette == V4L2_PIX_FMT_YUYV && colours == ZM_COLOUR_RGB32 ) { - conversion_fptr = &zm_convert_yuyv_rgba; - subpixelorder = ZM_SUBPIX_ORDER_RGBA; - } else if ( palette == V4L2_PIX_FMT_RGB555 && colours == ZM_COLOUR_RGB24 ) { - conversion_fptr = &zm_convert_rgb555_rgb; - subpixelorder = ZM_SUBPIX_ORDER_RGB; - } else if ( palette == V4L2_PIX_FMT_RGB555 && colours == ZM_COLOUR_RGB32 ) { - conversion_fptr = &zm_convert_rgb555_rgba; - subpixelorder = ZM_SUBPIX_ORDER_RGBA; - } else if ( palette == V4L2_PIX_FMT_RGB565 && colours == ZM_COLOUR_RGB24 ) { - conversion_fptr = &zm_convert_rgb565_rgb; - subpixelorder = ZM_SUBPIX_ORDER_RGB; - } else if ( palette == V4L2_PIX_FMT_RGB565 && colours == ZM_COLOUR_RGB32 ) { - conversion_fptr = &zm_convert_rgb565_rgba; - subpixelorder = ZM_SUBPIX_ORDER_RGBA; + } else if (palette == V4L2_PIX_FMT_BGR32 && colours == ZM_COLOUR_GRAY8) { + conversion_fptr = &std_convert_bgra_gray8; + subpixelorder = ZM_SUBPIX_ORDER_NONE; + } else if (palette == V4L2_PIX_FMT_YUYV && colours == ZM_COLOUR_GRAY8) { + /* Fast YUYV->Grayscale conversion by extracting the Y channel */ + if (config.cpu_extensions && sse_version >= 35) { + conversion_fptr = &ssse3_convert_yuyv_gray8; + Debug(2,"Using SSSE3 YUYV->grayscale fast conversion"); } else { - Fatal("Unable to find a suitable format conversion for the selected palette and target colorspace."); + conversion_fptr = &std_convert_yuyv_gray8; + Debug(2,"Using standard YUYV->grayscale fast conversion"); } - } // end if conversion_type == 2 - } // end if needs conversion - } // end if v4l2 + subpixelorder = ZM_SUBPIX_ORDER_NONE; + } else if (palette == V4L2_PIX_FMT_YUYV && colours == ZM_COLOUR_RGB24) { + conversion_fptr = &zm_convert_yuyv_rgb; + subpixelorder = ZM_SUBPIX_ORDER_RGB; + } else if (palette == V4L2_PIX_FMT_YUYV && colours == ZM_COLOUR_RGB32) { + conversion_fptr = &zm_convert_yuyv_rgba; + subpixelorder = ZM_SUBPIX_ORDER_RGBA; + } else if (palette == V4L2_PIX_FMT_RGB555 && colours == ZM_COLOUR_RGB24) { + conversion_fptr = &zm_convert_rgb555_rgb; + subpixelorder = ZM_SUBPIX_ORDER_RGB; + } else if (palette == V4L2_PIX_FMT_RGB555 && colours == ZM_COLOUR_RGB32) { + conversion_fptr = &zm_convert_rgb555_rgba; + subpixelorder = ZM_SUBPIX_ORDER_RGBA; + } else if (palette == V4L2_PIX_FMT_RGB565 && colours == ZM_COLOUR_RGB24) { + conversion_fptr = &zm_convert_rgb565_rgb; + subpixelorder = ZM_SUBPIX_ORDER_RGB; + } else if (palette == V4L2_PIX_FMT_RGB565 && colours == ZM_COLOUR_RGB32) { + conversion_fptr = &zm_convert_rgb565_rgba; + subpixelorder = ZM_SUBPIX_ORDER_RGBA; + } else { + Fatal("Unable to find a suitable format conversion for the selected palette and target colorspace."); + } + } // end if conversion_type == 2 + } // end if needs conversion last_camera = this; Debug(3, "Selected subpixelorder: %u", subpixelorder); /* Initialize swscale stuff */ - if ( capture and (conversion_type == 1) ) { + if (capture and (conversion_type == 1)) { tmpPicture = av_frame_alloc(); - if ( !tmpPicture ) + if (!tmpPicture) Fatal("Could not allocate temporary picture"); unsigned int pSize = av_image_get_buffer_size(imagePixFormat, width, height, 1); - if ( pSize != imagesize ) { + if (pSize != imagesize) { Fatal("Image size mismatch. Required: %d Available: %llu", pSize, imagesize); } @@ -460,23 +457,23 @@ LocalCamera::LocalCamera( width, height, imagePixFormat, SWS_BICUBIC, nullptr, nullptr, nullptr); - if ( !imgConversionContext ) { + if (!imgConversionContext) { Fatal("Unable to initialise image scaling context"); } } else { tmpPicture = nullptr; imgConversionContext = nullptr; } // end if capture and conversion_tye == swscale - if ( capture and device_prime ) + if (capture and device_prime) Initialise(); } // end LocalCamera::LocalCamera LocalCamera::~LocalCamera() { - if ( device_prime && capture ) + if (device_prime && capture) Terminate(); /* Clean up swscale stuff */ - if ( capture && (conversion_type == 1) ) { + if (capture && (conversion_type == 1)) { sws_freeContext(imgConversionContext); imgConversionContext = nullptr; @@ -492,251 +489,248 @@ int LocalCamera::Close() { void LocalCamera::Initialise() { Debug(3, "Opening video device %s", device.c_str()); - //if ( (vid_fd = open( device.c_str(), O_RDWR|O_NONBLOCK, 0 )) < 0 ) - if ( (vid_fd = open(device.c_str(), O_RDWR, 0)) < 0 ) + if ((vid_fd = open(device.c_str(), O_RDWR, 0)) < 0) Fatal("Failed to open video device %s: %s", device.c_str(), strerror(errno)); struct stat st; - if ( stat(device.c_str(), &st) < 0 ) + if (stat(device.c_str(), &st) < 0) Fatal("Failed to stat video device %s: %s", device.c_str(), strerror(errno)); - if ( !S_ISCHR(st.st_mode) ) + if (!S_ISCHR(st.st_mode)) Fatal("File %s is not device file: %s", device.c_str(), strerror(errno)); Debug(2, "V4L2 support enabled, using V4L%d api", v4l_version); - if ( v4l_version == 2 ) { - struct v4l2_capability vid_cap; + struct v4l2_capability vid_cap; - Debug(3, "Checking video device capabilities"); - if ( vidioctl(vid_fd, VIDIOC_QUERYCAP, &vid_cap) < 0 ) - Fatal("Failed to query video device: %s", strerror(errno)); + Debug(3, "Checking video device capabilities"); + if ( vidioctl(vid_fd, VIDIOC_QUERYCAP, &vid_cap) < 0 ) + Fatal("Failed to query video device: %s", strerror(errno)); - if ( !(vid_cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) ) - Fatal("Video device is not video capture device"); + if ( !(vid_cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) ) + Fatal("Video device is not video capture device"); - if ( !(vid_cap.capabilities & V4L2_CAP_STREAMING) ) - Fatal("Video device does not support streaming i/o"); + if ( !(vid_cap.capabilities & V4L2_CAP_STREAMING) ) + Fatal("Video device does not support streaming i/o"); - Debug(3, "Setting up video format"); + Debug(3, "Setting up video format"); - memset(&v4l2_data.fmt, 0, sizeof(v4l2_data.fmt)); - v4l2_data.fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + memset(&v4l2_data.fmt, 0, sizeof(v4l2_data.fmt)); + v4l2_data.fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - if ( vidioctl( vid_fd, VIDIOC_G_FMT, &v4l2_data.fmt ) < 0 ) - Fatal("Failed to get video format: %s", strerror(errno)); + if ( vidioctl( vid_fd, VIDIOC_G_FMT, &v4l2_data.fmt ) < 0 ) + Fatal("Failed to get video format: %s", strerror(errno)); - Debug(4, - " v4l2_data.fmt.type = %08x\n" - " v4l2_data.fmt.fmt.pix.width = %d\n" - " v4l2_data.fmt.fmt.pix.height = %d\n" - " v4l2_data.fmt.fmt.pix.pixelformat = %08x\n" - " v4l2_data.fmt.fmt.pix.field = %08x\n" - " v4l2_data.fmt.fmt.pix.bytesperline = %d\n" - " v4l2_data.fmt.fmt.pix.sizeimage = %d\n" - " v4l2_data.fmt.fmt.pix.colorspace = %08x\n" - " v4l2_data.fmt.fmt.pix.priv = %08x\n" - , v4l2_data.fmt.type - , v4l2_data.fmt.fmt.pix.width - , v4l2_data.fmt.fmt.pix.height - , v4l2_data.fmt.fmt.pix.pixelformat - , v4l2_data.fmt.fmt.pix.field - , v4l2_data.fmt.fmt.pix.bytesperline - , v4l2_data.fmt.fmt.pix.sizeimage - , v4l2_data.fmt.fmt.pix.colorspace - , v4l2_data.fmt.fmt.pix.priv - ); + Debug(4, + " v4l2_data.fmt.type = %08x\n" + " v4l2_data.fmt.fmt.pix.width = %d\n" + " v4l2_data.fmt.fmt.pix.height = %d\n" + " v4l2_data.fmt.fmt.pix.pixelformat = %08x\n" + " v4l2_data.fmt.fmt.pix.field = %08x\n" + " v4l2_data.fmt.fmt.pix.bytesperline = %d\n" + " v4l2_data.fmt.fmt.pix.sizeimage = %d\n" + " v4l2_data.fmt.fmt.pix.colorspace = %08x\n" + " v4l2_data.fmt.fmt.pix.priv = %08x\n" + , v4l2_data.fmt.type + , v4l2_data.fmt.fmt.pix.width + , v4l2_data.fmt.fmt.pix.height + , v4l2_data.fmt.fmt.pix.pixelformat + , v4l2_data.fmt.fmt.pix.field + , v4l2_data.fmt.fmt.pix.bytesperline + , v4l2_data.fmt.fmt.pix.sizeimage + , v4l2_data.fmt.fmt.pix.colorspace + , v4l2_data.fmt.fmt.pix.priv + ); - v4l2_data.fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - v4l2_data.fmt.fmt.pix.width = width; - v4l2_data.fmt.fmt.pix.height = height; - v4l2_data.fmt.fmt.pix.pixelformat = palette; + v4l2_data.fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + v4l2_data.fmt.fmt.pix.width = width; + v4l2_data.fmt.fmt.pix.height = height; + v4l2_data.fmt.fmt.pix.pixelformat = palette; - if ( (extras & 0xff) != 0 ) { - v4l2_data.fmt.fmt.pix.field = (v4l2_field)(extras & 0xff); + if ((extras & 0xff) != 0) { + v4l2_data.fmt.fmt.pix.field = (v4l2_field)(extras & 0xff); - if ( vidioctl(vid_fd, VIDIOC_S_FMT, &v4l2_data.fmt) < 0 ) { - Warning("Failed to set V4L2 field to %d, falling back to auto", (extras & 0xff)); - v4l2_data.fmt.fmt.pix.field = V4L2_FIELD_ANY; - if ( vidioctl(vid_fd, VIDIOC_S_FMT, &v4l2_data.fmt) < 0 ) { - Fatal("Failed to set video format: %s", strerror(errno)); - } - } - } else { - if ( vidioctl(vid_fd, VIDIOC_S_FMT, &v4l2_data.fmt) < 0 ) { - Error("Failed to set video format: %s", strerror(errno)); + if (vidioctl(vid_fd, VIDIOC_S_FMT, &v4l2_data.fmt) < 0) { + Warning("Failed to set V4L2 field to %d, falling back to auto", (extras & 0xff)); + v4l2_data.fmt.fmt.pix.field = V4L2_FIELD_ANY; + if (vidioctl(vid_fd, VIDIOC_S_FMT, &v4l2_data.fmt) < 0) { + Fatal("Failed to set video format: %s", strerror(errno)); } } - - /* Note VIDIOC_S_FMT may change width and height. */ - Debug(4, - " v4l2_data.fmt.type = %08x\n" - " v4l2_data.fmt.fmt.pix.width = %d\n" - " v4l2_data.fmt.fmt.pix.height = %d\n" - " v4l2_data.fmt.fmt.pix.pixelformat = %08x\n" - " v4l2_data.fmt.fmt.pix.field = %08x\n" - " v4l2_data.fmt.fmt.pix.bytesperline = %d\n" - " v4l2_data.fmt.fmt.pix.sizeimage = %d\n" - " v4l2_data.fmt.fmt.pix.colorspace = %08x\n" - " v4l2_data.fmt.fmt.pix.priv = %08x\n" - , v4l2_data.fmt.type - , v4l2_data.fmt.fmt.pix.width - , v4l2_data.fmt.fmt.pix.height - , v4l2_data.fmt.fmt.pix.pixelformat - , v4l2_data.fmt.fmt.pix.field - , v4l2_data.fmt.fmt.pix.bytesperline - , v4l2_data.fmt.fmt.pix.sizeimage - , v4l2_data.fmt.fmt.pix.colorspace - , v4l2_data.fmt.fmt.pix.priv - ); - - if ( v4l2_data.fmt.fmt.pix.width != width ) { - Warning("Failed to set requested width"); - } - if ( v4l2_data.fmt.fmt.pix.height != height ) { - Warning("Failed to set requested height"); + } else { + if (vidioctl(vid_fd, VIDIOC_S_FMT, &v4l2_data.fmt) < 0) { + Error("Failed to set video format: %s", strerror(errno)); } + } - /* Buggy driver paranoia. */ - unsigned int min; - min = v4l2_data.fmt.fmt.pix.width * 2; - if ( v4l2_data.fmt.fmt.pix.bytesperline < min ) - v4l2_data.fmt.fmt.pix.bytesperline = min; - min = v4l2_data.fmt.fmt.pix.bytesperline * v4l2_data.fmt.fmt.pix.height; - if ( v4l2_data.fmt.fmt.pix.sizeimage < min ) - v4l2_data.fmt.fmt.pix.sizeimage = min; + /* Note VIDIOC_S_FMT may change width and height. */ + Debug(4, + " v4l2_data.fmt.type = %08x\n" + " v4l2_data.fmt.fmt.pix.width = %d\n" + " v4l2_data.fmt.fmt.pix.height = %d\n" + " v4l2_data.fmt.fmt.pix.pixelformat = %08x\n" + " v4l2_data.fmt.fmt.pix.field = %08x\n" + " v4l2_data.fmt.fmt.pix.bytesperline = %d\n" + " v4l2_data.fmt.fmt.pix.sizeimage = %d\n" + " v4l2_data.fmt.fmt.pix.colorspace = %08x\n" + " v4l2_data.fmt.fmt.pix.priv = %08x\n" + , v4l2_data.fmt.type + , v4l2_data.fmt.fmt.pix.width + , v4l2_data.fmt.fmt.pix.height + , v4l2_data.fmt.fmt.pix.pixelformat + , v4l2_data.fmt.fmt.pix.field + , v4l2_data.fmt.fmt.pix.bytesperline + , v4l2_data.fmt.fmt.pix.sizeimage + , v4l2_data.fmt.fmt.pix.colorspace + , v4l2_data.fmt.fmt.pix.priv + ); - if ( palette == V4L2_PIX_FMT_JPEG || palette == V4L2_PIX_FMT_MJPEG ) { - v4l2_jpegcompression jpeg_comp; - if ( vidioctl(vid_fd, VIDIOC_G_JPEGCOMP, &jpeg_comp) < 0 ) { - if ( errno == EINVAL ) { - Debug(2, "JPEG compression options are not available"); - } else { - Warning("Failed to get JPEG compression options: %s", strerror(errno)); - } + if (v4l2_data.fmt.fmt.pix.width != width) { + Warning("Failed to set requested width"); + } + if (v4l2_data.fmt.fmt.pix.height != height) { + Warning("Failed to set requested height"); + } + + /* Buggy driver paranoia. */ + unsigned int min; + min = v4l2_data.fmt.fmt.pix.width * 2; + if (v4l2_data.fmt.fmt.pix.bytesperline < min) + v4l2_data.fmt.fmt.pix.bytesperline = min; + min = v4l2_data.fmt.fmt.pix.bytesperline * v4l2_data.fmt.fmt.pix.height; + if (v4l2_data.fmt.fmt.pix.sizeimage < min) + v4l2_data.fmt.fmt.pix.sizeimage = min; + + if (palette == V4L2_PIX_FMT_JPEG || palette == V4L2_PIX_FMT_MJPEG) { + v4l2_jpegcompression jpeg_comp; + if (vidioctl(vid_fd, VIDIOC_G_JPEGCOMP, &jpeg_comp) < 0) { + if (errno == EINVAL) { + Debug(2, "JPEG compression options are not available"); } else { - /* Set flags and quality. MJPEG should not have the huffman tables defined */ - if ( palette == V4L2_PIX_FMT_MJPEG ) { - jpeg_comp.jpeg_markers |= V4L2_JPEG_MARKER_DQT | V4L2_JPEG_MARKER_DRI; - } else { - jpeg_comp.jpeg_markers |= V4L2_JPEG_MARKER_DQT | V4L2_JPEG_MARKER_DRI | V4L2_JPEG_MARKER_DHT; - } - jpeg_comp.quality = 85; - - /* Update the JPEG options */ - if ( vidioctl(vid_fd, VIDIOC_S_JPEGCOMP, &jpeg_comp) < 0 ) { - Warning("Failed to set JPEG compression options: %s", strerror(errno)); - } else { - if ( vidioctl(vid_fd, VIDIOC_G_JPEGCOMP, &jpeg_comp) < 0 ) { - Debug(3,"Failed to get updated JPEG compression options: %s", strerror(errno)); - } else { - Debug(4, "JPEG quality: %d, markers: %#x", - jpeg_comp.quality, jpeg_comp.jpeg_markers); - } - } - } - } // end if JPEG/MJPEG - - Debug(3, "Setting up request buffers"); - - memset(&v4l2_data.reqbufs, 0, sizeof(v4l2_data.reqbufs)); - if ( channel_count > 1 ) { - Debug(3, "Channel count is %d", channel_count); - if ( v4l_multi_buffer ){ - v4l2_data.reqbufs.count = 2*channel_count; - } else { - v4l2_data.reqbufs.count = 1; + Warning("Failed to get JPEG compression options: %s", strerror(errno)); } } else { - v4l2_data.reqbufs.count = 8; - } - Debug(3, "Request buffers count is %d", v4l2_data.reqbufs.count); - - v4l2_data.reqbufs.type = v4l2_data.fmt.type; - v4l2_data.reqbufs.memory = V4L2_MEMORY_MMAP; - - if ( vidioctl(vid_fd, VIDIOC_REQBUFS, &v4l2_data.reqbufs) < 0 ) { - if ( errno == EINVAL ) { - Fatal("Unable to initialise memory mapping, unsupported in device"); + /* Set flags and quality. MJPEG should not have the huffman tables defined */ + if (palette == V4L2_PIX_FMT_MJPEG) { + jpeg_comp.jpeg_markers |= V4L2_JPEG_MARKER_DQT | V4L2_JPEG_MARKER_DRI; } else { - Fatal("Unable to initialise memory mapping: %s", strerror(errno)); + jpeg_comp.jpeg_markers |= V4L2_JPEG_MARKER_DQT | V4L2_JPEG_MARKER_DRI | V4L2_JPEG_MARKER_DHT; + } + jpeg_comp.quality = 85; + + /* Update the JPEG options */ + if (vidioctl(vid_fd, VIDIOC_S_JPEGCOMP, &jpeg_comp) < 0) { + Warning("Failed to set JPEG compression options: %s", strerror(errno)); + } else { + if (vidioctl(vid_fd, VIDIOC_G_JPEGCOMP, &jpeg_comp) < 0) { + Debug(3,"Failed to get updated JPEG compression options: %s", strerror(errno)); + } else { + Debug(4, "JPEG quality: %d, markers: %#x", + jpeg_comp.quality, jpeg_comp.jpeg_markers); + } } } + } // end if JPEG/MJPEG - if ( v4l2_data.reqbufs.count < (v4l_multi_buffer?2:1) ) - Fatal("Insufficient buffer memory %d on video device", v4l2_data.reqbufs.count); + Debug(3, "Setting up request buffers"); - Debug(3, "Setting up data buffers: Channels %d MultiBuffer %d Buffers: %d", - channel_count, v4l_multi_buffer, v4l2_data.reqbufs.count); - - v4l2_data.buffers = new V4L2MappedBuffer[v4l2_data.reqbufs.count]; - capturePictures = new AVFrame *[v4l2_data.reqbufs.count]; - - for ( unsigned int i = 0; i < v4l2_data.reqbufs.count; i++ ) { - struct v4l2_buffer vid_buf; - - memset(&vid_buf, 0, sizeof(vid_buf)); - - //vid_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - vid_buf.type = v4l2_data.fmt.type; - //vid_buf.memory = V4L2_MEMORY_MMAP; - vid_buf.memory = v4l2_data.reqbufs.memory; - vid_buf.index = i; - - if ( vidioctl(vid_fd, VIDIOC_QUERYBUF, &vid_buf) < 0 ) - Fatal("Unable to query video buffer: %s", strerror(errno)); - - v4l2_data.buffers[i].length = vid_buf.length; - v4l2_data.buffers[i].start = mmap(nullptr, vid_buf.length, PROT_READ|PROT_WRITE, MAP_SHARED, vid_fd, vid_buf.m.offset); - - if ( v4l2_data.buffers[i].start == MAP_FAILED ) - Fatal("Can't map video buffer %u (%u bytes) to memory: %s(%d)", - i, vid_buf.length, strerror(errno), errno); - - capturePictures[i] = av_frame_alloc(); - - if ( !capturePictures[i] ) - Fatal("Could not allocate picture"); - - av_image_fill_arrays( - capturePictures[i]->data, - capturePictures[i]->linesize, - (uint8_t*)v4l2_data.buffers[i].start, - capturePixFormat, - v4l2_data.fmt.fmt.pix.width, - v4l2_data.fmt.fmt.pix.height, - 1); - } // end foreach request buf - - Debug(3, "Configuring video source"); - - if ( vidioctl(vid_fd, VIDIOC_S_INPUT, &channel) < 0 ) { - Fatal("Failed to set camera source %d: %s", channel, strerror(errno)); + memset(&v4l2_data.reqbufs, 0, sizeof(v4l2_data.reqbufs)); + if (channel_count > 1) { + Debug(3, "Channel count is %d", channel_count); + if (v4l_multi_buffer){ + v4l2_data.reqbufs.count = 2*channel_count; + } else { + v4l2_data.reqbufs.count = 1; } - - struct v4l2_input input; - v4l2_std_id stdId; - - memset(&input, 0, sizeof(input)); - input.index = channel; - - if ( vidioctl(vid_fd, VIDIOC_ENUMINPUT, &input) < 0 ) { - Fatal("Failed to enumerate input %d: %s", channel, strerror(errno)); - } - - if ( (input.std != V4L2_STD_UNKNOWN) && ((input.std & standard) == V4L2_STD_UNKNOWN) ) { - Error("Device does not support video standard %d", standard); - } - - stdId = standard; - if ((vidioctl(vid_fd, VIDIOC_S_STD, &stdId) < 0)) { - Error("Failed to set video standard %d: %d %s", standard, errno, strerror(errno)); - } - - Contrast(contrast); - Brightness(brightness); - Hue(hue); - Colour(colour); + } else { + v4l2_data.reqbufs.count = 8; } + Debug(3, "Request buffers count is %d", v4l2_data.reqbufs.count); + + v4l2_data.reqbufs.type = v4l2_data.fmt.type; + v4l2_data.reqbufs.memory = V4L2_MEMORY_MMAP; + + if (vidioctl(vid_fd, VIDIOC_REQBUFS, &v4l2_data.reqbufs) < 0) { + if (errno == EINVAL) { + Fatal("Unable to initialise memory mapping, unsupported in device"); + } else { + Fatal("Unable to initialise memory mapping: %s", strerror(errno)); + } + } + + if (v4l2_data.reqbufs.count < (v4l_multi_buffer?2:1)) + Fatal("Insufficient buffer memory %d on video device", v4l2_data.reqbufs.count); + + Debug(3, "Setting up data buffers: Channels %d MultiBuffer %d Buffers: %d", + channel_count, v4l_multi_buffer, v4l2_data.reqbufs.count); + + v4l2_data.buffers = new V4L2MappedBuffer[v4l2_data.reqbufs.count]; + capturePictures = new AVFrame *[v4l2_data.reqbufs.count]; + + for (unsigned int i = 0; i < v4l2_data.reqbufs.count; i++) { + struct v4l2_buffer vid_buf; + + memset(&vid_buf, 0, sizeof(vid_buf)); + + //vid_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + vid_buf.type = v4l2_data.fmt.type; + //vid_buf.memory = V4L2_MEMORY_MMAP; + vid_buf.memory = v4l2_data.reqbufs.memory; + vid_buf.index = i; + + if (vidioctl(vid_fd, VIDIOC_QUERYBUF, &vid_buf) < 0) + Fatal("Unable to query video buffer: %s", strerror(errno)); + + v4l2_data.buffers[i].length = vid_buf.length; + v4l2_data.buffers[i].start = mmap(nullptr, vid_buf.length, PROT_READ|PROT_WRITE, MAP_SHARED, vid_fd, vid_buf.m.offset); + + if (v4l2_data.buffers[i].start == MAP_FAILED) + Fatal("Can't map video buffer %u (%u bytes) to memory: %s(%d)", + i, vid_buf.length, strerror(errno), errno); + + capturePictures[i] = av_frame_alloc(); + + if (!capturePictures[i]) + Fatal("Could not allocate picture"); + + av_image_fill_arrays( + capturePictures[i]->data, + capturePictures[i]->linesize, + (uint8_t*)v4l2_data.buffers[i].start, + capturePixFormat, + v4l2_data.fmt.fmt.pix.width, + v4l2_data.fmt.fmt.pix.height, + 1); + } // end foreach request buf + + Debug(3, "Configuring video source"); + + if (vidioctl(vid_fd, VIDIOC_S_INPUT, &channel) < 0) { + Fatal("Failed to set camera source %d: %s", channel, strerror(errno)); + } + + struct v4l2_input input; + v4l2_std_id stdId; + + memset(&input, 0, sizeof(input)); + input.index = channel; + + if (vidioctl(vid_fd, VIDIOC_ENUMINPUT, &input) < 0) { + Fatal("Failed to enumerate input %d: %s", channel, strerror(errno)); + } + + if ((input.std != V4L2_STD_UNKNOWN) && ((input.std & standard) == V4L2_STD_UNKNOWN)) { + Error("Device does not support video standard %d", standard); + } + + stdId = standard; + if ((vidioctl(vid_fd, VIDIOC_S_STD, &stdId) < 0)) { + Error("Failed to set video standard %d: %d %s", standard, errno, strerror(errno)); + } + + Contrast(contrast); + Brightness(brightness); + Hue(hue); + Colour(colour); } // end LocalCamera::Initialize void LocalCamera::Terminate() { @@ -1170,126 +1164,47 @@ bool LocalCamera::GetCurrentSettings( return true; } -int LocalCamera::Brightness(int p_brightness) { - if ( v4l_version == 2 ) { - struct v4l2_control vid_control; +int LocalCamera::Control(int vid_id, int newvalue) { + struct v4l2_control vid_control; - memset(&vid_control, 0, sizeof(vid_control)); - vid_control.id = V4L2_CID_BRIGHTNESS; + memset(&vid_control, 0, sizeof(vid_control)); + vid_control.id = vid_id; - if ( vidioctl(vid_fd, VIDIOC_G_CTRL, &vid_control) < 0 ) { - if ( errno != EINVAL ) { - Error("Unable to query brightness: %s", strerror(errno)); - } else { - Warning("Brightness control is not supported"); - } - //Info( "Brightness 1 %d", vid_control.value ); - } else if ( p_brightness >= 0 ) { - vid_control.value = p_brightness; - - //Info( "Brightness 2 %d", vid_control.value ); - /* The driver may clamp the value or return ERANGE, ignored here */ - if ( vidioctl(vid_fd, VIDIOC_S_CTRL, &vid_control) ) { - if ( errno != ERANGE ) { - Error("Unable to set brightness: %s", strerror(errno)); - } else { - Warning("Given brightness value (%d) may be out-of-range", p_brightness); - } - } - //Info( "Brightness 3 %d", vid_control.value ); + if (vidioctl(vid_fd, VIDIOC_G_CTRL, &vid_control) < 0) { + if (errno != EINVAL) { + Error("Unable to query control: %s", strerror(errno)); + } else { + Warning("Control is not supported"); + } + } else if (newvalue >= 0) { + vid_control.value = newvalue; + + /* The driver may clamp the value or return ERANGE, ignored here */ + if ( vidioctl(vid_fd, VIDIOC_S_CTRL, &vid_control) ) { + if (errno != ERANGE) { + Error("Unable to set control: %s", strerror(errno)); + } else { + Warning("Given control value (%d) may be out-of-range", newvalue); + } } - return vid_control.value; } - return -1; + return vid_control.value; +} + +int LocalCamera::Brightness(int p_brightness) { + return Control(V4L2_CID_BRIGHTNESS, p_brightness); } int LocalCamera::Hue(int p_hue) { - if ( v4l_version == 2 ) { - struct v4l2_control vid_control; - - memset( &vid_control, 0, sizeof(vid_control) ); - vid_control.id = V4L2_CID_HUE; - - if ( vidioctl(vid_fd, VIDIOC_G_CTRL, &vid_control) < 0 ) { - if ( errno != EINVAL ) - Error("Unable to query hue: %s", strerror(errno)); - else - Warning("Hue control is not supported"); - } else if ( p_hue >= 0 ) { - vid_control.value = p_hue; - - /* The driver may clamp the value or return ERANGE, ignored here */ - if ( vidioctl(vid_fd, VIDIOC_S_CTRL, &vid_control) < 0 ) { - if ( errno != ERANGE ) { - Error("Unable to set hue: %s", strerror(errno)); - } else { - Warning("Given hue value (%d) may be out-of-range", p_hue); - } - } - } - return vid_control.value; - } - return -1; + return Control(V4L2_CID_HUE, p_hue); } int LocalCamera::Colour( int p_colour ) { - if ( v4l_version == 2 ) { - struct v4l2_control vid_control; - - memset(&vid_control, 0, sizeof(vid_control)); - vid_control.id = V4L2_CID_SATURATION; - - if ( vidioctl(vid_fd, VIDIOC_G_CTRL, &vid_control) < 0 ) { - if ( errno != EINVAL ) { - Error("Unable to query saturation: %s", strerror(errno)); - } else { - Warning("Saturation control is not supported"); - } - } else if ( p_colour >= 0 ) { - vid_control.value = p_colour; - - /* The driver may clamp the value or return ERANGE, ignored here */ - if ( vidioctl(vid_fd, VIDIOC_S_CTRL, &vid_control) < 0 ) { - if ( errno != ERANGE ) { - Error("Unable to set saturation: %s", strerror(errno)); - } else { - Warning("Given saturation value (%d) may be out-of-range", p_colour); - } - } - } - return vid_control.value; - } - return -1; + return Control(V4L2_CID_SATURATION, p_colour); } -int LocalCamera::Contrast( int p_contrast ) { - if ( v4l_version == 2 ) { - struct v4l2_control vid_control; - - memset(&vid_control, 0, sizeof(vid_control)); - vid_control.id = V4L2_CID_CONTRAST; - - if ( vidioctl(vid_fd, VIDIOC_G_CTRL, &vid_control) < 0 ) { - if ( errno != EINVAL ) { - Error("Unable to query contrast: %s", strerror(errno)); - } else { - Warning("Contrast control is not supported"); - } - } else if ( p_contrast >= 0 ) { - vid_control.value = p_contrast; - - /* The driver may clamp the value or return ERANGE, ignored here */ - if ( vidioctl(vid_fd, VIDIOC_S_CTRL, &vid_control) ) { - if ( errno != ERANGE ) { - Error("Unable to set contrast: %s", strerror(errno)); - } else { - Warning("Given contrast value (%d) may be out-of-range", p_contrast); - } - } - } - return vid_control.value; - } - return -1; +int LocalCamera::Contrast(int p_contrast) { + return Control(V4L2_CID_CONTRAST, p_contrast); } int LocalCamera::PrimeCapture() { diff --git a/src/zm_local_camera.h b/src/zm_local_camera.h index f6991c5de..f702b816f 100644 --- a/src/zm_local_camera.h +++ b/src/zm_local_camera.h @@ -113,6 +113,7 @@ public: int Palette() const { return palette; } int Extras() const { return extras; } + int Control(int vid_id, int newvalue=-1 ); int Brightness( int p_brightness=-1 ) override; int Hue( int p_hue=-1 ) override; int Colour( int p_colour=-1 ) override;