CHROMIUM: driver: media: virtio: Support prepending SPS/PPS to IDR.
This CL adds support for the V4L2_CID_MPEG_VIDEO_PREPEND_SPSPPS_TO_IDR
control to the virtio encoder. When this control is enabled SPS and PPS
NAL units are prepended to IDR frames, to improve the resilience of
encoded video streams.
Signed-off-by: David Staessens <dstaessens@google.com>
BUG=b:161495502
TEST=tast run DUT arc.VideoEncodeAccel.h264_192p_i420_vm
Cq-Depend: chromium:3060098
Change-Id: Icfa925e9e463b75aa78c664ec52750959e5be6ea
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/third_party/kernel/+/3058721
Reviewed-by: Keiichi Watanabe <keiichiw@chromium.org>
Tested-by: David Staessens <dstaessens@chromium.org>
Commit-Queue: David Staessens <dstaessens@chromium.org>
(cherry picked from commit 44afe397a3fc77e313916bf940af307fab61603b)
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/third_party/kernel/+/3088815
diff --git a/drivers/media/virtio/virtio_video.h b/drivers/media/virtio/virtio_video.h
index 4b823a2..9e949ee 100644
--- a/drivers/media/virtio/virtio_video.h
+++ b/drivers/media/virtio/virtio_video.h
@@ -94,6 +94,7 @@ struct video_control_info {
uint32_t bitrate;
uint32_t bitrate_peak;
uint32_t bitrate_mode;
+ uint32_t prepend_spspps_to_idr;
bool is_updated;
};
diff --git a/drivers/media/virtio/virtio_video_device.c b/drivers/media/virtio/virtio_video_device.c
index 1908a52..1cef520 100644
--- a/drivers/media/virtio/virtio_video_device.c
+++ b/drivers/media/virtio/virtio_video_device.c
@@ -977,6 +977,14 @@ static int virtio_video_device_open(struct file *file)
v4l2_err(&vv->v4l2_dev, "failed to get stream bitrate mode\n");
goto err_stream_get_params;
}
+
+ ret = virtio_video_cmd_get_control(vv, stream,
+ VIRTIO_VIDEO_CONTROL_PREPEND_SPSPPS_TO_IDR);
+ if (ret) {
+ v4l2_err(&vv->v4l2_dev,
+ "failed to get stream prepend SPS/PPS to IDR control\n");
+ goto err_stream_get_params;
+ }
}
mutex_init(&stream->vq_mutex);
diff --git a/drivers/media/virtio/virtio_video_enc.c b/drivers/media/virtio/virtio_video_enc.c
index 9a9499c..34fd14c1 100644
--- a/drivers/media/virtio/virtio_video_enc.c
+++ b/drivers/media/virtio/virtio_video_enc.c
@@ -141,6 +141,10 @@ static int virtio_video_enc_s_ctrl(struct v4l2_ctrl *ctrl)
ret = virtio_video_cmd_set_control(vv, stream->stream_id,
control, 1 /*ignored*/);
break;
+ case V4L2_CID_MPEG_VIDEO_PREPEND_SPSPPS_TO_IDR:
+ ret = virtio_video_cmd_set_control(vv, stream->stream_id,
+ control, ctrl->val);
+ break;
default:
ret = -EINVAL;
break;
@@ -248,6 +252,12 @@ int virtio_video_enc_init_ctrls(struct virtio_video_stream *stream)
V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME,
0, 0, 0, 0);
+ v4l2_ctrl_new_std(&stream->ctrl_handler,
+ &virtio_video_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_PREPEND_SPSPPS_TO_IDR,
+ 0, 1,
+ 1, 0);
+
if (stream->ctrl_handler.error)
return stream->ctrl_handler.error;
diff --git a/drivers/media/virtio/virtio_video_helpers.c b/drivers/media/virtio/virtio_video_helpers.c
index 2a7f30d3..3435ec0 100644
--- a/drivers/media/virtio/virtio_video_helpers.c
+++ b/drivers/media/virtio/virtio_video_helpers.c
@@ -191,6 +191,8 @@ static struct virtio_video_convert_table control_table[] = {
{ VIRTIO_VIDEO_CONTROL_LEVEL, V4L2_CID_MPEG_VIDEO_H264_LEVEL },
{ VIRTIO_VIDEO_CONTROL_FORCE_KEYFRAME,
V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME },
+ { VIRTIO_VIDEO_CONTROL_PREPEND_SPSPPS_TO_IDR,
+ V4L2_CID_MPEG_VIDEO_PREPEND_SPSPPS_TO_IDR },
{ 0 },
};
diff --git a/drivers/media/virtio/virtio_video_vq.c b/drivers/media/virtio/virtio_video_vq.c
index 10194ab..f6b983d 100644
--- a/drivers/media/virtio/virtio_video_vq.c
+++ b/drivers/media/virtio/virtio_video_vq.c
@@ -1036,6 +1036,28 @@ virtio_video_cmd_get_ctrl_bitrate_mode_cb(struct virtio_video *vv,
wake_up(&vv->wq);
}
+static void
+virtio_video_cmd_get_ctrl_prepend_spspps_to_idr(struct virtio_video *vv,
+ struct virtio_video_vbuffer *vbuf)
+{
+ struct virtio_video_get_control_resp *resp =
+ (struct virtio_video_get_control_resp *)vbuf->resp_buf;
+ struct virtio_video_control_val_prepend_spspps_to_idr *resp_ps = NULL;
+ struct virtio_video_stream *stream = vbuf->priv;
+ struct video_control_info *control = &stream->control;
+
+ if (!control)
+ return;
+
+ resp_ps = (void *)((char *) resp +
+ sizeof(struct virtio_video_get_control_resp));
+
+ control->prepend_spspps_to_idr = le32_to_cpu(
+ resp_ps->prepend_spspps_to_idr);
+ control->is_updated = true;
+ wake_up(&vv->wq);
+}
+
int virtio_video_cmd_get_control(struct virtio_video *vv,
struct virtio_video_stream *stream,
uint32_t virtio_ctrl)
@@ -1071,6 +1093,11 @@ int virtio_video_cmd_get_control(struct virtio_video *vv,
resp_size += sizeof(struct virtio_video_control_val_bitrate_mode);
cb = &virtio_video_cmd_get_ctrl_bitrate_mode_cb;
break;
+ case VIRTIO_VIDEO_CONTROL_PREPEND_SPSPPS_TO_IDR:
+ resp_size += sizeof(
+ struct virtio_video_control_val_prepend_spspps_to_idr);
+ cb = &virtio_video_cmd_get_ctrl_prepend_spspps_to_idr;
+ break;
default:
return -1;
}
@@ -1112,6 +1139,7 @@ int virtio_video_cmd_set_control(struct virtio_video *vv, uint32_t stream_id,
struct virtio_video_control_val_bitrate *ctrl_b = NULL;
struct virtio_video_control_val_bitrate_peak *ctrl_bp = NULL;
struct virtio_video_control_val_bitrate_mode *ctrl_bm = NULL;
+ struct virtio_video_control_val_prepend_spspps_to_idr *ctrl_ps = NULL;
size_t size;
if (!vv || value == 0)
@@ -1136,6 +1164,9 @@ int virtio_video_cmd_set_control(struct virtio_video *vv, uint32_t stream_id,
case VIRTIO_VIDEO_CONTROL_FORCE_KEYFRAME:
size = 0;
break;
+ case VIRTIO_VIDEO_CONTROL_PREPEND_SPSPPS_TO_IDR:
+ size = sizeof(struct virtio_video_control_val_prepend_spspps_to_idr);
+ break;
default:
return -1;
}
@@ -1177,6 +1208,11 @@ int virtio_video_cmd_set_control(struct virtio_video *vv, uint32_t stream_id,
case VIRTIO_VIDEO_CONTROL_FORCE_KEYFRAME:
// Button controls have no value.
break;
+ case VIRTIO_VIDEO_CONTROL_PREPEND_SPSPPS_TO_IDR:
+ ctrl_ps = (void *)((char *)req_p +
+ sizeof(struct virtio_video_set_control));
+ ctrl_ps->prepend_spspps_to_idr = cpu_to_le32(value);
+ break;
}
return virtio_video_queue_cmd_buffer(vv, vbuf);
diff --git a/include/uapi/linux/virtio_video.h b/include/uapi/linux/virtio_video.h
index 9a888e0..69e4c68 100644
--- a/include/uapi/linux/virtio_video.h
+++ b/include/uapi/linux/virtio_video.h
@@ -392,6 +392,7 @@ enum virtio_video_control_type {
VIRTIO_VIDEO_CONTROL_FORCE_KEYFRAME,
VIRTIO_VIDEO_CONTROL_BITRATE_MODE,
VIRTIO_VIDEO_CONTROL_BITRATE_PEAK,
+ VIRTIO_VIDEO_CONTROL_PREPEND_SPSPPS_TO_IDR,
};
struct virtio_video_query_control_profile {
@@ -463,6 +464,11 @@ struct virtio_video_control_val_level {
__u8 padding[4];
};
+struct virtio_video_control_val_prepend_spspps_to_idr {
+ __le32 prepend_spspps_to_idr;
+ __u8 padding[4];
+};
+
struct virtio_video_get_control_resp {
struct virtio_video_cmd_hdr hdr;
/* Followed by one of struct virtio_video_control_val_* */