blob: d9345e61f0df9089e8e280bbf7093108ea0daf6b [file] [log] [blame] [edit]
/* Copyright 2023 The ChromiumOS Authors
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
/* Setters for abstract models of V4L2 entities.
*
* If the model has an fd for a kernel device set, then the setters will
* propagate the new values to the kernel.
*
* Return values:
* - on success: true
* - on failure: false
*/
#include "tools/mctk/entity.h"
#include <linux/media.h>
#include <linux/types.h>
#include <linux/v4l2-mediabus.h>
#include <linux/v4l2-subdev.h>
#include <linux/videodev2.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <optional>
#include <string>
#include <vector>
#include "tools/mctk/debug.h"
/* This is a macro instead of a function so we can easily print
* the ioctl name in the error message.
*/
#define VIDIOC_S_WRAP(ioctl_num, ptr) \
do { \
if (this->fd_) { \
if (ioctl(this->fd_.value(), (ioctl_num), &(ptr)) < 0) { \
MCTK_PERROR("ioctl(" #ioctl_num ")"); \
return false; \
} \
} \
\
return true; \
} while (0);
bool V4lMcEntity::SetAudio(struct v4l2_audio& audio) {
maindev_.audio = audio;
VIDIOC_S_WRAP(VIDIOC_S_AUDIO, audio);
}
bool V4lMcEntity::SetAudout(struct v4l2_audioout& audout) {
maindev_.audout = audout;
VIDIOC_S_WRAP(VIDIOC_S_AUDOUT, audout);
}
bool V4lMcEntity::SetCrop(__u32 type, struct v4l2_rect& c) {
switch (type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
maindev_.crop_video_capture = c;
break;
case V4L2_BUF_TYPE_VIDEO_OUTPUT:
maindev_.crop_video_output = c;
break;
case V4L2_BUF_TYPE_VIDEO_OVERLAY:
maindev_.crop_video_overlay = c;
break;
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
maindev_.crop_video_capture_mplane = c;
break;
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
maindev_.crop_video_output_mplane = c;
break;
default:
/* Only 5 types valid for VIDIOC_S_CROP as of kernel 6.5 */
MCTK_ERR("Not setting cropping rectangle for unknown buffer type.");
return false;
}
struct v4l2_crop crop = {.type = type, .c = c};
VIDIOC_S_WRAP(VIDIOC_S_CROP, crop);
}
bool V4lMcEntity::SetDvTimings(struct v4l2_dv_timings& dv_timings) {
maindev_.dv_timings = dv_timings;
VIDIOC_S_WRAP(VIDIOC_S_DV_TIMINGS, dv_timings);
}
bool V4lMcEntity::SetSubdevDvTimings(
struct v4l2_dv_timings& subdev_dv_timings) {
maindev_.subdev_dv_timings = subdev_dv_timings;
VIDIOC_S_WRAP(VIDIOC_SUBDEV_S_DV_TIMINGS, subdev_dv_timings);
}
bool V4lMcEntity::SetFbuf(struct v4l2_framebuffer& fbuf) {
maindev_.fbuf = fbuf;
VIDIOC_S_WRAP(VIDIOC_S_FBUF, fbuf);
}
bool V4lMcEntity::SetFmtVideoCapture(struct v4l2_pix_format& pix) {
maindev_.fmt_video_capture = pix;
struct v4l2_format format = {};
format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE, format.fmt.pix = pix;
VIDIOC_S_WRAP(VIDIOC_S_FMT, format);
}
bool V4lMcEntity::SetFmtVideoOutput(struct v4l2_pix_format& pix) {
maindev_.fmt_video_output = pix;
struct v4l2_format format = {};
format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT, format.fmt.pix = pix;
VIDIOC_S_WRAP(VIDIOC_S_FMT, format);
}
bool V4lMcEntity::SetFmtVideoOverlay(struct v4l2_window& win) {
maindev_.fmt_video_overlay = win;
struct v4l2_format format = {};
format.type = V4L2_BUF_TYPE_VIDEO_OVERLAY, format.fmt.win = win;
VIDIOC_S_WRAP(VIDIOC_S_FMT, format);
}
bool V4lMcEntity::SetFmtVbiCapture(struct v4l2_vbi_format& vbi) {
maindev_.fmt_vbi_capture = vbi;
struct v4l2_format format = {};
format.type = V4L2_BUF_TYPE_VBI_CAPTURE, format.fmt.vbi = vbi;
VIDIOC_S_WRAP(VIDIOC_S_FMT, format);
}
bool V4lMcEntity::SetFmtVbiOutput(struct v4l2_vbi_format& vbi) {
maindev_.fmt_vbi_output = vbi;
struct v4l2_format format = {};
format.type = V4L2_BUF_TYPE_VBI_OUTPUT, format.fmt.vbi = vbi;
VIDIOC_S_WRAP(VIDIOC_S_FMT, format);
}
bool V4lMcEntity::SetFmtSlicedVbiCapture(
struct v4l2_sliced_vbi_format& sliced) {
maindev_.fmt_sliced_vbi_capture = sliced;
struct v4l2_format format = {};
format.type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE, format.fmt.sliced = sliced;
VIDIOC_S_WRAP(VIDIOC_S_FMT, format);
}
bool V4lMcEntity::SetFmtSlicedVbiOutput(struct v4l2_sliced_vbi_format& sliced) {
maindev_.fmt_sliced_vbi_output = sliced;
struct v4l2_format format = {};
format.type = V4L2_BUF_TYPE_SLICED_VBI_OUTPUT, format.fmt.sliced = sliced;
VIDIOC_S_WRAP(VIDIOC_S_FMT, format);
}
bool V4lMcEntity::SetFmtVideoOutputOverlay(struct v4l2_window& win) {
maindev_.fmt_video_output_overlay = win;
struct v4l2_format format = {};
format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY, format.fmt.win = win;
VIDIOC_S_WRAP(VIDIOC_S_FMT, format);
}
bool V4lMcEntity::SetFmtVideoCaptureMplane(
struct v4l2_pix_format_mplane& pix_mp) {
maindev_.fmt_video_capture_mplane = pix_mp;
struct v4l2_format format = {};
format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, format.fmt.pix_mp = pix_mp;
VIDIOC_S_WRAP(VIDIOC_S_FMT, format);
}
bool V4lMcEntity::SetFmtVideoOutputMplane(
struct v4l2_pix_format_mplane& pix_mp) {
maindev_.fmt_video_output_mplane = pix_mp;
struct v4l2_format format = {};
format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, format.fmt.pix_mp = pix_mp;
VIDIOC_S_WRAP(VIDIOC_S_FMT, format);
}
bool V4lMcEntity::SetFmtSdrCapture(struct v4l2_sdr_format& sdr) {
maindev_.fmt_sdr_capture = sdr;
struct v4l2_format format = {};
format.type = V4L2_BUF_TYPE_SDR_CAPTURE, format.fmt.sdr = sdr;
VIDIOC_S_WRAP(VIDIOC_S_FMT, format);
}
bool V4lMcEntity::SetFmtSdrOutput(struct v4l2_sdr_format& sdr) {
maindev_.fmt_sdr_output = sdr;
struct v4l2_format format = {};
format.type = V4L2_BUF_TYPE_SDR_OUTPUT, format.fmt.sdr = sdr;
VIDIOC_S_WRAP(VIDIOC_S_FMT, format);
}
bool V4lMcEntity::SetFmtMetaCapture(struct v4l2_meta_format& meta) {
maindev_.fmt_meta_capture = meta;
struct v4l2_format format = {};
format.type = V4L2_BUF_TYPE_META_CAPTURE, format.fmt.meta = meta;
VIDIOC_S_WRAP(VIDIOC_S_FMT, format);
}
bool V4lMcEntity::SetFmtMetaOutput(struct v4l2_meta_format& meta) {
maindev_.fmt_meta_output = meta;
struct v4l2_format format = {};
format.type = V4L2_BUF_TYPE_META_OUTPUT, format.fmt.meta = meta;
VIDIOC_S_WRAP(VIDIOC_S_FMT, format);
}
bool V4lMcEntity::SetInput(int input) {
maindev_.input = input;
VIDIOC_S_WRAP(VIDIOC_S_INPUT, input);
}
bool V4lMcEntity::SetJpegcomp(struct v4l2_jpegcompression& jpegcomp) {
maindev_.jpegcomp = jpegcomp;
VIDIOC_S_WRAP(VIDIOC_S_JPEGCOMP, jpegcomp);
}
bool V4lMcEntity::SetOutput(int output) {
maindev_.output = output;
VIDIOC_S_WRAP(VIDIOC_S_OUTPUT, output);
}
bool V4lMcEntity::SetParmVideoCapture(struct v4l2_captureparm& capture) {
maindev_.parm_video_capture = capture;
struct v4l2_streamparm streamparm = {};
streamparm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
streamparm.parm.capture = capture;
VIDIOC_S_WRAP(VIDIOC_S_PARM, streamparm);
}
bool V4lMcEntity::SetParmVideoOutput(struct v4l2_outputparm& output) {
maindev_.parm_video_output = output;
struct v4l2_streamparm streamparm = {};
streamparm.type = V4L2_BUF_TYPE_VIDEO_OUTPUT, streamparm.parm.output = output;
VIDIOC_S_WRAP(VIDIOC_S_PARM, streamparm);
}
bool V4lMcEntity::SetParmVideoOverlay(struct v4l2_outputparm& output) {
maindev_.parm_video_overlay = output;
struct v4l2_streamparm streamparm = {};
streamparm.type = V4L2_BUF_TYPE_VIDEO_OVERLAY,
streamparm.parm.output = output;
VIDIOC_S_WRAP(VIDIOC_S_PARM, streamparm);
}
bool V4lMcEntity::SetParmVbiCapture(struct v4l2_captureparm& capture) {
maindev_.parm_vbi_capture = capture;
struct v4l2_streamparm streamparm = {};
streamparm.type = V4L2_BUF_TYPE_VBI_CAPTURE,
streamparm.parm.capture = capture;
VIDIOC_S_WRAP(VIDIOC_S_PARM, streamparm);
}
bool V4lMcEntity::SetParmVbiOutput(struct v4l2_outputparm& output) {
maindev_.parm_vbi_output = output;
struct v4l2_streamparm streamparm = {};
streamparm.type = V4L2_BUF_TYPE_VBI_OUTPUT, streamparm.parm.output = output;
VIDIOC_S_WRAP(VIDIOC_S_PARM, streamparm);
}
bool V4lMcEntity::SetParmSlicedVbiCapture(struct v4l2_captureparm& capture) {
maindev_.parm_sliced_vbi_capture = capture;
struct v4l2_streamparm streamparm = {};
streamparm.type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE,
streamparm.parm.capture = capture;
VIDIOC_S_WRAP(VIDIOC_S_PARM, streamparm);
}
bool V4lMcEntity::SetParmSlicedVbiOutput(struct v4l2_outputparm& output) {
maindev_.parm_sliced_vbi_output = output;
struct v4l2_streamparm streamparm = {};
streamparm.type = V4L2_BUF_TYPE_SLICED_VBI_OUTPUT,
streamparm.parm.output = output;
VIDIOC_S_WRAP(VIDIOC_S_PARM, streamparm);
}
bool V4lMcEntity::SetParmVideoOutputOverlay(struct v4l2_outputparm& output) {
maindev_.parm_video_output_overlay = output;
struct v4l2_streamparm streamparm = {};
streamparm.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY,
streamparm.parm.output = output;
VIDIOC_S_WRAP(VIDIOC_S_PARM, streamparm);
}
bool V4lMcEntity::SetParmVideoCaptureMplane(struct v4l2_captureparm& capture) {
maindev_.parm_video_capture_mplane = capture;
struct v4l2_streamparm streamparm = {};
streamparm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
streamparm.parm.capture = capture;
VIDIOC_S_WRAP(VIDIOC_S_PARM, streamparm);
}
bool V4lMcEntity::SetParmVideoOutputMplane(struct v4l2_outputparm& output) {
maindev_.parm_video_output_mplane = output;
struct v4l2_streamparm streamparm = {};
streamparm.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
streamparm.parm.output = output;
VIDIOC_S_WRAP(VIDIOC_S_PARM, streamparm);
}
bool V4lMcEntity::SetParmSdrCapture(struct v4l2_captureparm& capture) {
maindev_.parm_sdr_capture = capture;
struct v4l2_streamparm streamparm = {};
streamparm.type = V4L2_BUF_TYPE_SDR_CAPTURE,
streamparm.parm.capture = capture;
VIDIOC_S_WRAP(VIDIOC_S_PARM, streamparm);
}
bool V4lMcEntity::SetParmSdrOutput(struct v4l2_outputparm& output) {
maindev_.parm_sdr_output = output;
struct v4l2_streamparm streamparm = {};
streamparm.type = V4L2_BUF_TYPE_SDR_OUTPUT, streamparm.parm.output = output;
VIDIOC_S_WRAP(VIDIOC_S_PARM, streamparm);
}
bool V4lMcEntity::SetParmMetaCapture(struct v4l2_captureparm& capture) {
maindev_.parm_meta_capture = capture;
struct v4l2_streamparm streamparm = {};
streamparm.type = V4L2_BUF_TYPE_META_CAPTURE,
streamparm.parm.capture = capture;
VIDIOC_S_WRAP(VIDIOC_S_PARM, streamparm);
}
bool V4lMcEntity::SetParmMetaOutput(struct v4l2_outputparm& output) {
maindev_.parm_meta_output = output;
struct v4l2_streamparm streamparm = {};
streamparm.type = V4L2_BUF_TYPE_META_OUTPUT, streamparm.parm.output = output;
VIDIOC_S_WRAP(VIDIOC_S_PARM, streamparm);
}
bool V4lMcEntity::SetPriority(enum v4l2_priority priority) {
maindev_.priority = priority;
VIDIOC_S_WRAP(VIDIOC_S_PRIORITY, priority);
}
bool V4lMcEntity::SetSelection(__u32 type, __u32 target, struct v4l2_rect& r) {
if (type < V4L2_BUF_TYPE_VIDEO_CAPTURE || type > V4L2_BUF_TYPE_META_OUTPUT)
/* Only 14 buffer types defined as of kernel 6.5 */
return false;
switch (target) {
case V4L2_SEL_TGT_CROP:
maindev_.selection[type - 1].crop_ = r;
break;
case V4L2_SEL_TGT_CROP_DEFAULT:
maindev_.selection[type - 1].crop_default_ = r;
break;
case V4L2_SEL_TGT_CROP_BOUNDS:
maindev_.selection[type - 1].crop_bounds_ = r;
break;
case V4L2_SEL_TGT_NATIVE_SIZE:
maindev_.selection[type - 1].native_size_ = r;
break;
case V4L2_SEL_TGT_COMPOSE:
maindev_.selection[type - 1].compose_ = r;
break;
case V4L2_SEL_TGT_COMPOSE_DEFAULT:
maindev_.selection[type - 1].compose_default_ = r;
break;
case V4L2_SEL_TGT_COMPOSE_BOUNDS:
maindev_.selection[type - 1].compose_bounds_ = r;
break;
case V4L2_SEL_TGT_COMPOSE_PADDED:
maindev_.selection[type - 1].compose_padded_ = r;
break;
default:
/* Only 8 targets defined as of kernel 6.5 */
return false;
}
struct v4l2_selection selection = {};
selection.type = type, selection.target = target;
selection.flags = 0; /* Expect the config to apply precisely */
selection.r = r;
VIDIOC_S_WRAP(VIDIOC_S_SELECTION, selection);
}
bool V4lMcEntity::SetStd(v4l2_std_id std) {
maindev_.std = std;
VIDIOC_S_WRAP(VIDIOC_S_STD, std);
}
bool V4lMcEntity::SetSubdevStd(v4l2_std_id subdev_std) {
maindev_.subdev_std = subdev_std;
#ifdef VIDIOC_SUBDEV_S_STD
VIDIOC_S_WRAP(VIDIOC_SUBDEV_S_STD, subdev_std);
#else
return true;
#endif /* VIDIOC_SUBDEV_S_STD */
}