diff options
Diffstat (limited to 'meta-egvirt/recipes-kernel/kernel-module-virtio-video/files/virtio_video_enc.c')
-rw-r--r-- | meta-egvirt/recipes-kernel/kernel-module-virtio-video/files/virtio_video_enc.c | 601 |
1 files changed, 0 insertions, 601 deletions
diff --git a/meta-egvirt/recipes-kernel/kernel-module-virtio-video/files/virtio_video_enc.c b/meta-egvirt/recipes-kernel/kernel-module-virtio-video/files/virtio_video_enc.c deleted file mode 100644 index 66730bdb..00000000 --- a/meta-egvirt/recipes-kernel/kernel-module-virtio-video/files/virtio_video_enc.c +++ /dev/null @@ -1,601 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* Encoder for virtio video device. - * - * Copyright 2020 OpenSynergy GmbH. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see <http://www.gnu.org/licenses/>. - */ - -#include <linux/version.h> -#include <media/v4l2-event.h> -#include <media/v4l2-ioctl.h> - -#include "virtio_video.h" - -static int virtio_video_enc_start_streaming(struct vb2_queue *vq, - unsigned int count) -{ - struct virtio_video_stream *stream = vb2_get_drv_priv(vq); - bool input_queue = V4L2_TYPE_IS_OUTPUT(vq->type); - - if (virtio_video_state(stream) == STREAM_STATE_ERROR) - return -EIO; - - if (virtio_video_state(stream) == STREAM_STATE_INIT || - (!input_queue && - virtio_video_state(stream) == STREAM_STATE_RESET) || - (input_queue && - virtio_video_state(stream) == STREAM_STATE_STOPPED)) - virtio_video_state_update(stream, STREAM_STATE_RUNNING); - - return 0; -} - -static void virtio_video_enc_stop_streaming(struct vb2_queue *vq) -{ - int ret, queue_type; - struct virtio_video_stream *stream = vb2_get_drv_priv(vq); - - if (V4L2_TYPE_IS_OUTPUT(vq->type)) - queue_type = VIRTIO_VIDEO_QUEUE_TYPE_INPUT; - else - queue_type = VIRTIO_VIDEO_QUEUE_TYPE_OUTPUT; - - ret = virtio_video_queue_release_buffers(stream, queue_type); - if (ret) - return; - - vb2_wait_for_all_buffers(vq); - - if (V4L2_TYPE_IS_OUTPUT(vq->type)) - virtio_video_state_update(stream, STREAM_STATE_STOPPED); - else - virtio_video_state_update(stream, STREAM_STATE_RESET); -} - -static const struct vb2_ops virtio_video_enc_qops = { - .queue_setup = virtio_video_queue_setup, - .buf_init = virtio_video_buf_init, - .buf_cleanup = virtio_video_buf_cleanup, - .buf_queue = virtio_video_buf_queue, - .start_streaming = virtio_video_enc_start_streaming, - .stop_streaming = virtio_video_enc_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, -}; - -static int virtio_video_enc_s_ctrl(struct v4l2_ctrl *ctrl) -{ - int ret = 0; - struct virtio_video_stream *stream = ctrl2stream(ctrl); - struct virtio_video_device *vvd = to_virtio_vd(stream->video_dev); - uint32_t control, value; - - if (virtio_video_state(stream) == STREAM_STATE_ERROR) - return -EIO; - - control = virtio_video_v4l2_control_to_virtio(ctrl->id); - - switch (ctrl->id) { - case V4L2_CID_MPEG_VIDEO_BITRATE: - ret = virtio_video_cmd_set_control(vvd, stream->stream_id, - control, ctrl->val); - break; - case V4L2_CID_MPEG_VIDEO_H264_LEVEL: - value = virtio_video_v4l2_level_to_virtio(ctrl->val); - ret = virtio_video_cmd_set_control(vvd, stream->stream_id, - control, value); - break; - case V4L2_CID_MPEG_VIDEO_H264_PROFILE: - value = virtio_video_v4l2_profile_to_virtio(ctrl->val); - ret = virtio_video_cmd_set_control(vvd, stream->stream_id, - control, value); - break; - default: - ret = -EINVAL; - break; - } - - return ret; -} - -static int virtio_video_enc_g_ctrl(struct v4l2_ctrl *ctrl) -{ - int ret = 0; - struct virtio_video_stream *stream = ctrl2stream(ctrl); - - if (virtio_video_state(stream) == STREAM_STATE_ERROR) - return -EIO; - - switch (ctrl->id) { - case V4L2_CID_MIN_BUFFERS_FOR_OUTPUT: - if (virtio_video_state(stream) >= STREAM_STATE_INIT) - ctrl->val = stream->in_info.min_buffers; - else - ctrl->val = 0; - break; - default: - ret = -EINVAL; - break; - } - - return ret; -} - -static const struct v4l2_ctrl_ops virtio_video_enc_ctrl_ops = { - .g_volatile_ctrl = virtio_video_enc_g_ctrl, - .s_ctrl = virtio_video_enc_s_ctrl, -}; - -int virtio_video_enc_init_ctrls(struct virtio_video_stream *stream) -{ - struct v4l2_ctrl *ctrl; - struct virtio_video_device *vvd = to_virtio_vd(stream->video_dev); - struct video_control_format *c_fmt = NULL; - - v4l2_ctrl_handler_init(&stream->ctrl_handler, 1); - - ctrl = v4l2_ctrl_new_std(&stream->ctrl_handler, - &virtio_video_enc_ctrl_ops, - V4L2_CID_MIN_BUFFERS_FOR_OUTPUT, - MIN_BUFS_MIN, MIN_BUFS_MAX, MIN_BUFS_STEP, - MIN_BUFS_DEF); - - if (ctrl) - ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE; - - list_for_each_entry(c_fmt, &vvd->controls_fmt_list, - controls_list_entry) { - switch (c_fmt->format) { - case V4L2_PIX_FMT_H264: - if (c_fmt->profile) - v4l2_ctrl_new_std_menu - (&stream->ctrl_handler, - &virtio_video_enc_ctrl_ops, - V4L2_CID_MPEG_VIDEO_H264_PROFILE, - c_fmt->profile->max, - c_fmt->profile->skip_mask, - c_fmt->profile->min); - - if (c_fmt->level) - v4l2_ctrl_new_std_menu - (&stream->ctrl_handler, - &virtio_video_enc_ctrl_ops, - V4L2_CID_MPEG_VIDEO_H264_LEVEL, - c_fmt->level->max, - c_fmt->level->skip_mask, - c_fmt->level->min); - break; - default: - v4l2_dbg(1, vvd->debug, - &vvd->v4l2_dev, "unsupported format\n"); - break; - } - } - - if (stream->control.bitrate) { - v4l2_ctrl_new_std(&stream->ctrl_handler, - &virtio_video_enc_ctrl_ops, - V4L2_CID_MPEG_VIDEO_BITRATE, - 1, S32_MAX, - 1, stream->control.bitrate); - } - - if (stream->ctrl_handler.error) - return stream->ctrl_handler.error; - - v4l2_ctrl_handler_setup(&stream->ctrl_handler); - - return 0; -} - -int virtio_video_enc_init_queues(void *priv, struct vb2_queue *src_vq, - struct vb2_queue *dst_vq) -{ - int ret; - struct virtio_video_stream *stream = priv; - struct virtio_video_device *vvd = to_virtio_vd(stream->video_dev); - struct device *dev = vvd->v4l2_dev.dev; - - src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; - src_vq->io_modes = VB2_MMAP | VB2_DMABUF; - src_vq->drv_priv = stream; - src_vq->buf_struct_size = sizeof(struct virtio_video_buffer); - src_vq->ops = &virtio_video_enc_qops; - src_vq->mem_ops = virtio_video_mem_ops(vvd); - src_vq->min_buffers_needed = stream->in_info.min_buffers; - src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; - src_vq->lock = &stream->vq_mutex; - src_vq->gfp_flags = virtio_video_gfp_flags(vvd); - src_vq->dev = dev; - - ret = vb2_queue_init(src_vq); - if (ret) - return ret; - - dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; - dst_vq->io_modes = VB2_MMAP | VB2_DMABUF; - dst_vq->drv_priv = stream; - dst_vq->buf_struct_size = sizeof(struct virtio_video_buffer); - dst_vq->ops = &virtio_video_enc_qops; - dst_vq->mem_ops = virtio_video_mem_ops(vvd); - dst_vq->min_buffers_needed = stream->out_info.min_buffers; - dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; - dst_vq->lock = &stream->vq_mutex; - dst_vq->gfp_flags = virtio_video_gfp_flags(vvd); - dst_vq->dev = dev; - - return vb2_queue_init(dst_vq); -} - -static int virtio_video_try_encoder_cmd(struct file *file, void *fh, - struct v4l2_encoder_cmd *cmd) -{ - struct virtio_video_stream *stream = file2stream(file); - struct virtio_video_device *vvd = video_drvdata(file); - - if (virtio_video_state(stream) == STREAM_STATE_ERROR) - return -EIO; - - if (virtio_video_state(stream) == STREAM_STATE_DRAIN) - return -EBUSY; - - switch (cmd->cmd) { - case V4L2_ENC_CMD_STOP: - case V4L2_ENC_CMD_START: - if (cmd->flags != 0) { - v4l2_err(&vvd->v4l2_dev, "flags=%u are not supported", - cmd->flags); - return -EINVAL; - } - break; - default: - return -EINVAL; - } - - return 0; -} - -static int virtio_video_encoder_cmd(struct file *file, void *fh, - struct v4l2_encoder_cmd *cmd) -{ - int ret; - struct vb2_queue *src_vq, *dst_vq; - struct virtio_video_stream *stream = file2stream(file); - struct virtio_video_device *vvd = video_drvdata(file); - - ret = virtio_video_try_encoder_cmd(file, fh, cmd); - if (ret < 0) - return ret; - - dst_vq = v4l2_m2m_get_vq(stream->fh.m2m_ctx, - V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); - - switch (cmd->cmd) { - case V4L2_ENC_CMD_START: - vb2_clear_last_buffer_dequeued(dst_vq); - virtio_video_state_update(stream, STREAM_STATE_RUNNING); - break; - case V4L2_ENC_CMD_STOP: - src_vq = v4l2_m2m_get_vq(stream->fh.m2m_ctx, - V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); - - if (!vb2_is_streaming(src_vq)) { - v4l2_dbg(1, vvd->debug, - &vvd->v4l2_dev, "output is not streaming\n"); - return 0; - } - - if (!vb2_is_streaming(dst_vq)) { - v4l2_dbg(1, vvd->debug, - &vvd->v4l2_dev, "capture is not streaming\n"); - return 0; - } - - ret = virtio_video_cmd_stream_drain(vvd, stream->stream_id); - if (ret) { - v4l2_err(&vvd->v4l2_dev, "failed to drain stream\n"); - return ret; - } - - virtio_video_state_update(stream, STREAM_STATE_DRAIN); - break; - default: - return -EINVAL; - } - - return 0; -} - -static int virtio_video_enc_enum_fmt_vid_cap(struct file *file, void *fh, - struct v4l2_fmtdesc *f) -{ - struct virtio_video_stream *stream = file2stream(file); - struct virtio_video_device *vvd = to_virtio_vd(stream->video_dev); - struct video_format *fmt; - int idx = 0; - - if (virtio_video_state(stream) == STREAM_STATE_ERROR) - return -EIO; - - if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) - return -EINVAL; - - if (f->index >= vvd->num_output_fmts) - return -EINVAL; - - list_for_each_entry(fmt, &vvd->output_fmt_list, formats_list_entry) { - if (f->index == idx) { - f->pixelformat = fmt->desc.format; - return 0; - } - idx++; - } - return -EINVAL; -} - -static int virtio_video_enc_enum_fmt_vid_out(struct file *file, void *fh, - struct v4l2_fmtdesc *f) -{ - struct virtio_video_stream *stream = file2stream(file); - struct virtio_video_device *vvd = to_virtio_vd(stream->video_dev); - struct video_format_info *info = NULL; - struct video_format *fmt = NULL; - unsigned long output_mask = 0; - int idx = 0, bit_num = 0; - - if (virtio_video_state(stream) == STREAM_STATE_ERROR) - return -EIO; - - if (f->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) - return -EINVAL; - - if (f->index >= vvd->num_input_fmts) - return -EINVAL; - - info = &stream->out_info; - list_for_each_entry(fmt, &vvd->output_fmt_list, formats_list_entry) { - if (info->fourcc_format == fmt->desc.format) { - output_mask = fmt->desc.mask; - break; - } - } - - if (output_mask == 0) - return -EINVAL; - - list_for_each_entry(fmt, &vvd->input_fmt_list, formats_list_entry) { - if (test_bit(bit_num, &output_mask)) { - if (f->index == idx) { - f->pixelformat = fmt->desc.format; - return 0; - } - idx++; - } - bit_num++; - } - return -EINVAL; -} - -static int virtio_video_enc_s_fmt(struct file *file, void *fh, - struct v4l2_format *f) -{ - int ret; - struct virtio_video_stream *stream = file2stream(file); - - ret = virtio_video_s_fmt(file, fh, f); - if (ret) - return ret; - - if (!V4L2_TYPE_IS_OUTPUT(f->type)) { - if (virtio_video_state(stream) == STREAM_STATE_IDLE) - virtio_video_state_update(stream, STREAM_STATE_INIT); - } - - return 0; -} - -static int virtio_video_enc_try_framerate(struct virtio_video_stream *stream, - unsigned int fps) -{ - int rate_idx; - struct video_format_frame *frame = NULL; - - if (stream->current_frame == NULL) - return -EINVAL; - - frame = stream->current_frame; - for (rate_idx = 0; rate_idx < frame->frame.num_rates; rate_idx++) { - struct virtio_video_format_range *frame_rate = - &frame->frame_rates[rate_idx]; - - if (within_range(frame_rate->min, fps, frame_rate->max)) - return 0; - } - - return -EINVAL; -} - -static void virtio_video_timeperframe_from_info(struct video_format_info *info, - struct v4l2_fract *timeperframe) -{ - timeperframe->numerator = 1; - timeperframe->denominator = info->frame_rate; -} - -static int virtio_video_enc_g_parm(struct file *file, void *priv, - struct v4l2_streamparm *a) -{ - struct virtio_video_stream *stream = file2stream(file); - struct virtio_video_device *vvd = to_virtio_vd(stream->video_dev); - struct v4l2_outputparm *out = &a->parm.output; - struct v4l2_fract *timeperframe = &out->timeperframe; - - if (virtio_video_state(stream) == STREAM_STATE_ERROR) - return -EIO; - - if (!V4L2_TYPE_IS_OUTPUT(a->type)) { - v4l2_err(&vvd->v4l2_dev, - "getting FPS is only possible for the output queue\n"); - return -EINVAL; - } - - out->capability = V4L2_CAP_TIMEPERFRAME; - virtio_video_timeperframe_from_info(&stream->in_info, timeperframe); - - return 0; -} - -static int virtio_video_enc_s_parm(struct file *file, void *priv, - struct v4l2_streamparm *a) -{ - int ret; - u64 frame_interval, frame_rate; - struct video_format_info info; - struct virtio_video_stream *stream = file2stream(file); - struct virtio_video_device *vvd = to_virtio_vd(stream->video_dev); - struct v4l2_outputparm *out = &a->parm.output; - struct v4l2_fract *timeperframe = &out->timeperframe; - - if (virtio_video_state(stream) == STREAM_STATE_ERROR) - return -EIO; - - if (V4L2_TYPE_IS_OUTPUT(a->type)) { - frame_interval = timeperframe->numerator * (u64)USEC_PER_SEC; - do_div(frame_interval, timeperframe->denominator); - if (!frame_interval) - return -EINVAL; - - frame_rate = (u64)USEC_PER_SEC; - do_div(frame_rate, frame_interval); - } else { - v4l2_err(&vvd->v4l2_dev, - "setting FPS is only possible for the output queue\n"); - return -EINVAL; - } - - ret = virtio_video_enc_try_framerate(stream, frame_rate); - if (ret) - return ret; - - virtio_video_format_fill_default_info(&info, &stream->in_info); - info.frame_rate = frame_rate; - - virtio_video_cmd_set_params(vvd, stream, &info, - VIRTIO_VIDEO_QUEUE_TYPE_INPUT); - virtio_video_stream_get_params(vvd, stream); - - out->capability = V4L2_CAP_TIMEPERFRAME; - virtio_video_timeperframe_from_info(&stream->in_info, timeperframe); - - return 0; -} - -static int virtio_video_enc_s_selection(struct file *file, void *fh, - struct v4l2_selection *sel) -{ - struct virtio_video_stream *stream = file2stream(file); - struct virtio_video_device *vvd = to_virtio_vd(stream->video_dev); - int ret; - - if (!V4L2_TYPE_IS_OUTPUT(sel->type)) - return -EINVAL; - - switch (sel->target) { - case V4L2_SEL_TGT_CROP: - stream->in_info.crop.top = sel->r.top; - stream->in_info.crop.left = sel->r.left; - stream->in_info.crop.width = sel->r.width; - stream->in_info.crop.height = sel->r.height; - break; - default: - return -EINVAL; - } - - ret = virtio_video_cmd_set_params(vvd, stream, &stream->in_info, - VIRTIO_VIDEO_QUEUE_TYPE_INPUT); - if (ret) - return -EINVAL; - - return virtio_video_cmd_get_params(vvd, stream, - VIRTIO_VIDEO_QUEUE_TYPE_INPUT); -} - -static const struct v4l2_ioctl_ops virtio_video_enc_ioctl_ops = { - .vidioc_querycap = virtio_video_querycap, - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) - .vidioc_enum_fmt_vid_cap = virtio_video_enc_enum_fmt_vid_cap, - .vidioc_enum_fmt_vid_out = virtio_video_enc_enum_fmt_vid_out, -#else - .vidioc_enum_fmt_vid_cap_mplane = virtio_video_enc_enum_fmt_vid_cap, - .vidioc_enum_fmt_vid_out_mplane = virtio_video_enc_enum_fmt_vid_out, -#endif - .vidioc_g_fmt_vid_cap_mplane = virtio_video_g_fmt, - .vidioc_s_fmt_vid_cap_mplane = virtio_video_enc_s_fmt, - - .vidioc_g_fmt_vid_out_mplane = virtio_video_g_fmt, - .vidioc_s_fmt_vid_out_mplane = virtio_video_enc_s_fmt, - - .vidioc_try_encoder_cmd = virtio_video_try_encoder_cmd, - .vidioc_encoder_cmd = virtio_video_encoder_cmd, - .vidioc_enum_frameintervals = virtio_video_enum_framemintervals, - .vidioc_enum_framesizes = virtio_video_enum_framesizes, - - .vidioc_g_selection = virtio_video_g_selection, - .vidioc_s_selection = virtio_video_enc_s_selection, - - .vidioc_reqbufs = virtio_video_reqbufs, - .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, - .vidioc_qbuf = virtio_video_qbuf, - .vidioc_dqbuf = virtio_video_dqbuf, - .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf, - .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs, - .vidioc_expbuf = v4l2_m2m_ioctl_expbuf, - - .vidioc_streamon = v4l2_m2m_ioctl_streamon, - .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, - - .vidioc_s_parm = virtio_video_enc_s_parm, - .vidioc_g_parm = virtio_video_enc_g_parm, - - .vidioc_subscribe_event = virtio_video_subscribe_event, - .vidioc_unsubscribe_event = v4l2_event_unsubscribe, -}; - -void *virtio_video_enc_get_fmt_list(struct virtio_video_device *vvd) -{ - return &vvd->output_fmt_list; -} - -static struct virtio_video_device_ops virtio_video_enc_ops = { - .init_ctrls = virtio_video_enc_init_ctrls, - .init_queues = virtio_video_enc_init_queues, - .get_fmt_list = virtio_video_enc_get_fmt_list, -}; - -int virtio_video_enc_init(struct virtio_video_device *vvd) -{ - ssize_t num; - struct video_device *vd = &vvd->video_dev; - - vd->ioctl_ops = &virtio_video_enc_ioctl_ops; - vvd->ops = &virtio_video_enc_ops; - - num = strscpy(vd->name, "stateful-encoder", sizeof(vd->name)); - if (num < 0) - return num; - - return 0; -} |