Spacing, remove tests for v4l2, move control setting/getting code to a single function.

This commit is contained in:
Isaac Connor 2021-10-05 13:50:41 -04:00
parent 1f04723f3a
commit 75a014321e
2 changed files with 351 additions and 435 deletions

View File

@ -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<uint8>((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() {

View File

@ -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;