meta-digi/meta-digi-arm/dynamic-layers/stm-st-stm32mp/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad/0070-v4l2codecs-encoder-add...

249 lines
8.9 KiB
Diff

From 6d9de5b60a9f26822ae28bb9d5fa788a80963ccd Mon Sep 17 00:00:00 2001
From: Hugues Fruchet <hugues.fruchet@foss.st.com>
Date: Tue, 12 Mar 2024 15:27:33 +0100
Subject: [PATCH] v4l2codecs: encoder: add rotation support
Add rotation support based on V4L2_CID_ROTATE control.
90 and 270 degrees rotation requires swap of src width & height
which must be take into account when allocating src pool.
Upstream-Status: Pending
---
sys/v4l2codecs/gstv4l2codech264enc.c | 15 ++++++----
sys/v4l2codecs/gstv4l2codecvp8enc.c | 15 ++++++----
sys/v4l2codecs/gstv4l2encoder.c | 41 ++++++++++++++++++++++++++++
3 files changed, 60 insertions(+), 11 deletions(-)
diff --git a/sys/v4l2codecs/gstv4l2codech264enc.c b/sys/v4l2codecs/gstv4l2codech264enc.c
index 0a195c8..921302a 100644
--- a/sys/v4l2codecs/gstv4l2codech264enc.c
+++ b/sys/v4l2codecs/gstv4l2codech264enc.c
@@ -76,6 +76,7 @@ struct _GstV4l2CodecH264Enc
GstV4l2Encoder *encoder;
GstVideoCodecState *output_state;
GstVideoInfo vinfo;
+ GstVideoInfo sink_info;
gint width;
gint height;
gint width_in_macroblocks;
@@ -276,7 +277,8 @@ gst_v4l2_codec_h264_enc_propose_allocation (GstVideoEncoder * encoder,
}
static gboolean
-gst_v4l2_codec_h264_enc_buffers_allocation (GstVideoEncoder * encoder)
+gst_v4l2_codec_h264_enc_buffers_allocation (GstVideoEncoder * encoder,
+ GstVideoCodecState * state)
{
GstV4l2CodecH264Enc *self = GST_V4L2_CODEC_H264_ENC (encoder);
@@ -306,7 +308,7 @@ gst_v4l2_codec_h264_enc_buffers_allocation (GstVideoEncoder * encoder)
return FALSE;
}
- self->src_pool = gst_v4l2_codec_pool_new (self->src_allocator, &self->vinfo);
+ self->src_pool = gst_v4l2_codec_pool_new (self->src_allocator, &state->info);
return TRUE;
}
@@ -705,6 +707,8 @@ gst_v4l2_codec_h264_enc_set_format (GstVideoEncoder * encoder,
gst_v4l2_codec_h264_enc_reset_allocation (self);
+ self->sink_info = state->info;
+
if (!gst_v4l2_encoder_set_src_fmt (self->encoder, &state->info,
V4L2_PIX_FMT_H264_SLICE)) {
GST_ELEMENT_ERROR (self, CORE, NEGOTIATION, ("Unsupported pixel format"),
@@ -713,7 +717,7 @@ gst_v4l2_codec_h264_enc_set_format (GstVideoEncoder * encoder,
return FALSE;
}
- if (!gst_v4l2_encoder_select_sink_format (self->encoder, &state->info,
+ if (!gst_v4l2_encoder_select_sink_format (self->encoder, &self->sink_info,
&self->vinfo)) {
GST_ELEMENT_ERROR (self, CORE, NEGOTIATION,
("Failed to configure H264 encoder"),
@@ -727,7 +731,8 @@ gst_v4l2_codec_h264_enc_set_format (GstVideoEncoder * encoder,
self->height = state->info.height;
GST_VIDEO_ENCODER_CLASS (parent_class)->set_format (encoder, state);
- gst_v4l2_codec_h264_enc_buffers_allocation (encoder);
+ gst_v4l2_codec_h264_enc_buffers_allocation (encoder, state);
+
self->width_in_macroblocks = (self->width + 15) / 16;
self->height_in_macroblocks = (self->height + 15) / 16;
self->first_frame = TRUE;
@@ -864,7 +869,7 @@ gst_v4l2_codec_h264_enc_copy_input_buffer (GstV4l2CodecH264Enc * self,
GstFlowReturn flow_ret;
gst_video_info_set_format (&src_vinfo, GST_VIDEO_INFO_FORMAT (&self->vinfo),
- self->width, self->height);
+ self->sink_info.width, self->sink_info.height);
flow_ret = gst_buffer_pool_acquire_buffer (GST_BUFFER_POOL (self->sink_pool),
&buffer, NULL);
diff --git a/sys/v4l2codecs/gstv4l2codecvp8enc.c b/sys/v4l2codecs/gstv4l2codecvp8enc.c
index 42c2b1b..4ec141c 100644
--- a/sys/v4l2codecs/gstv4l2codecvp8enc.c
+++ b/sys/v4l2codecs/gstv4l2codecvp8enc.c
@@ -72,6 +72,7 @@ struct _GstV4l2CodecVp8Enc
GstV4l2Encoder *encoder;
GstVideoCodecState *output_state;
GstVideoInfo vinfo;
+ GstVideoInfo sink_info;
gint width;
gint height;
guint qp_max, qp_min;
@@ -249,7 +250,8 @@ gst_v4l2_codec_vp8_enc_propose_allocation (GstVideoEncoder * encoder,
}
static gboolean
-gst_v4l2_codec_vp8_enc_buffers_allocation (GstVideoEncoder * encoder)
+gst_v4l2_codec_vp8_enc_buffers_allocation (GstVideoEncoder * encoder,
+ GstVideoCodecState * state)
{
GstV4l2CodecVp8Enc *self = GST_V4L2_CODEC_VP8_ENC (encoder);
@@ -279,8 +281,7 @@ gst_v4l2_codec_vp8_enc_buffers_allocation (GstVideoEncoder * encoder)
return FALSE;
}
- self->src_pool = gst_v4l2_codec_pool_new (self->src_allocator, &self->vinfo);
-
+ self->src_pool = gst_v4l2_codec_pool_new (self->src_allocator, &state->info);
return TRUE;
}
@@ -298,6 +299,8 @@ gst_v4l2_codec_vp8_enc_set_format (GstVideoEncoder * encoder,
gst_v4l2_codec_vp8_enc_reset_allocation (self);
+ self->sink_info = state->info;
+
if (!gst_v4l2_encoder_set_src_fmt (self->encoder, &state->info,
V4L2_PIX_FMT_VP8_FRAME)) {
GST_ELEMENT_ERROR (self, CORE, NEGOTIATION, ("Unsupported pixel format"),
@@ -306,7 +309,7 @@ gst_v4l2_codec_vp8_enc_set_format (GstVideoEncoder * encoder,
return FALSE;
}
- if (!gst_v4l2_encoder_select_sink_format (self->encoder, &state->info,
+ if (!gst_v4l2_encoder_select_sink_format (self->encoder, &self->sink_info,
&self->vinfo)) {
GST_ELEMENT_ERROR (self, CORE, NEGOTIATION,
("Failed to configure VP8 encoder"),
@@ -318,7 +321,7 @@ gst_v4l2_codec_vp8_enc_set_format (GstVideoEncoder * encoder,
self->width = state->info.width;
self->height = state->info.height;
- gst_v4l2_codec_vp8_enc_buffers_allocation (encoder);
+ gst_v4l2_codec_vp8_enc_buffers_allocation (encoder, state);
if (self->output_state)
gst_video_codec_state_unref (self->output_state);
@@ -445,7 +448,7 @@ gst_v4l2_codec_vp8_enc_copy_input_buffer (GstV4l2CodecVp8Enc * self,
GstFlowReturn flow_ret;
gst_video_info_set_format (&src_vinfo, GST_VIDEO_INFO_FORMAT (&self->vinfo),
- self->width, self->height);
+ self->sink_info.width, self->sink_info.height);
flow_ret = gst_buffer_pool_acquire_buffer (GST_BUFFER_POOL (self->sink_pool),
&buffer, NULL);
diff --git a/sys/v4l2codecs/gstv4l2encoder.c b/sys/v4l2codecs/gstv4l2encoder.c
index 27f03e9..2532dc3 100644
--- a/sys/v4l2codecs/gstv4l2encoder.c
+++ b/sys/v4l2codecs/gstv4l2encoder.c
@@ -44,6 +44,7 @@ enum
PROP_0,
PROP_MEDIA_DEVICE,
PROP_VIDEO_DEVICE,
+ PROP_ROTATION,
};
struct _GstV4l2Request
@@ -95,6 +96,7 @@ struct _GstV4l2Encoder
gchar *media_device;
gchar *video_device;
guint render_delay;
+ guint rotation;
/* detected features */
gboolean supports_holding_capture;
@@ -687,6 +689,29 @@ gst_v4l2_encoder_set_src_fmt (GstV4l2Encoder * self, GstVideoInfo * info,
gint width = info->width;
gint height = info->height;
+ /* Apply rotation, this will affect src width/height */
+ if (self->rotation) {
+ struct v4l2_control ctl = { 0, };
+
+ ctl.id = V4L2_CID_ROTATE;
+ ctl.value = self->rotation;
+ ret = ioctl (self->video_fd, VIDIOC_S_CTRL, &ctl);
+ if (ret < 0) {
+ GST_ERROR_OBJECT (self, "VIDIOC_S_CTRL failed: %s", g_strerror (errno));
+ return FALSE;
+ }
+
+ if (self->rotation == 90 || self->rotation == 270) {
+ /*
+ * Swap width & height, this will trigger a call
+ * to S_FMT to let driver know the final
+ * rotated resolution
+ */
+ width = info->height;
+ height = info->width;
+ }
+ }
+
ret = ioctl (self->video_fd, VIDIOC_G_FMT, &fmt);
if (ret < 0) {
GST_ERROR_OBJECT (self, "VIDIOC_G_FMT failed: %s", g_strerror (errno));
@@ -718,6 +743,10 @@ gst_v4l2_encoder_set_src_fmt (GstV4l2Encoder * self, GstVideoInfo * info,
return FALSE;
}
+ /* Stick to driver negotiated resolution */
+ info->width = fmt.fmt.pix_mp.width;
+ info->height = fmt.fmt.pix_mp.height;
+
return TRUE;
}
@@ -1114,6 +1143,12 @@ gst_v4l2_encoder_install_properties (GObjectClass * gobject_class,
g_param_spec_string ("video-device", "Video Device Path",
"Path to the video device node", video_device_path,
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (gobject_class, PROP_ROTATION,
+ g_param_spec_uint ("rotation", "Rotation",
+ "Set rotation angle in degrees",
+ 0, 270, 0,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT));
}
void
@@ -1131,6 +1166,9 @@ gst_v4l2_encoder_set_property (GObject * object, guint prop_id,
g_free (self->video_device);
self->video_device = g_value_dup_string (value);
break;
+ case PROP_ROTATION:
+ self->rotation = g_value_get_uint (value);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -1150,6 +1188,9 @@ gst_v4l2_encoder_get_property (GObject * object, guint prop_id,
case PROP_VIDEO_DEVICE:
g_value_set_string (value, self->video_device);
break;
+ case PROP_ROTATION:
+ g_value_set_uint (value, self->rotation);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
--
2.25.1