All of lore.kernel.org
 help / color / mirror / Atom feed
From: Arun Iyengar <aiyengar1990@gmail.com>
To: Mauro Carvalho Chehab <mchehab@kernel.org>
Cc: linux-media@vger.kernel.org, linux-kernel@vger.kernel.org,
	 Paul Kocialkowski <paulk@sys-base.io>,
	 Nicolas Dufresne <nicolas.dufresne@collabora.com>,
	 Hans Verkuil <hverkuil@kernel.org>,
	Arun Iyengar <aiyengar1990@gmail.com>
Subject: [PATCH RFC 08/10] media: v4l2-hevc-enc: Add QP limits for the I pictures
Date: Tue, 10 Nov 2026 10:07:38 +0000	[thread overview]
Message-ID: <20261110-hevc-encode-uapi-v1-8-38ae9fcfedd4@gmail.com> (raw)
In-Reply-To: <20261110-hevc-encode-uapi-v1-0-38ae9fcfedd4@gmail.com>

The frame rate control of the core limits all pictures to the range of
V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP and V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP. The
I pictures, coded several QP steps below the P pictures, then reach very
low QP values at high bitrates, where they cost many bits for little
quality.

Take the limits of the I pictures from V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_MIN_QP
and V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_MAX_QP when the driver has them, with
a frame rate control. Without these controls, nothing changes.

Signed-off-by: Arun Iyengar <aiyengar1990@gmail.com>
---
 drivers/media/v4l2-core/v4l2-hevc-enc.c | 24 +++++++++++++++++++++---
 include/media/v4l2-hevc-enc.h           |  7 +++++++
 2 files changed, 28 insertions(+), 3 deletions(-)

diff --git a/drivers/media/v4l2-core/v4l2-hevc-enc.c b/drivers/media/v4l2-core/v4l2-hevc-enc.c
index a167c4af6288..2e0ba832b868 100644
--- a/drivers/media/v4l2-core/v4l2-hevc-enc.c
+++ b/drivers/media/v4l2-core/v4l2-hevc-enc.c
@@ -645,6 +645,12 @@ static void prepare_rc(struct v4l2_hevc_enc *enc,
 	state->qp_min = enc_ctrl_val(enc, V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP,
 				     -qp_bd_offset);
 	state->qp_max = enc_ctrl_val(enc, V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP, 51);
+	state->qp_min_i = enc_ctrl_val(enc,
+				       V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_MIN_QP,
+				       state->qp_min);
+	state->qp_max_i = enc_ctrl_val(enc,
+				       V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_MAX_QP,
+				       state->qp_max);
 	state->qp_i = enc_ctrl_val(enc, V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_QP, 30);
 	state->qp_p = enc_ctrl_val(enc, V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_QP,
 				   state->qp_i);
@@ -1072,10 +1078,23 @@ static bool rc_core_cbr(const struct v4l2_hevc_enc *enc,
 	       !(enc->rc_ops && enc->rc_ops->estimate);
 }
 
+/* QP limits of the picture: the I picture ones with a frame rate control */
+static int rc_clamp_qp(const struct v4l2_hevc_enc_state *state, int qp)
+{
+	int qp_bd_offset = 6 * state->sps.bit_depth_luma_minus8;
+
+	if (state->frame_rc_enable &&
+	    state->encode.slice_type == V4L2_HEVC_SLICE_TYPE_I)
+		qp = clamp(qp, state->qp_min_i, state->qp_max_i);
+	else
+		qp = clamp(qp, state->qp_min, state->qp_max);
+
+	return clamp(qp, -qp_bd_offset, 51);
+}
+
 static int rc_step(struct v4l2_hevc_enc *enc)
 {
 	struct v4l2_hevc_enc_state *state = &enc->state_active;
-	int qp_bd_offset = 6 * state->sps.bit_depth_luma_minus8;
 	u8 slice_type = state->encode.slice_type;
 	unsigned int range;
 	int qp, ret;
@@ -1114,8 +1133,7 @@ static int rc_step(struct v4l2_hevc_enc *enc)
 			return ret;
 	}
 
-	qp = clamp(qp, state->qp_min, state->qp_max);
-	enc->qp = clamp(qp, -qp_bd_offset, 51);
+	enc->qp = rc_clamp_qp(state, qp);
 
 	return 0;
 }
diff --git a/include/media/v4l2-hevc-enc.h b/include/media/v4l2-hevc-enc.h
index 3db131370c56..f1d3da3269f1 100644
--- a/include/media/v4l2-hevc-enc.h
+++ b/include/media/v4l2-hevc-enc.h
@@ -128,6 +128,11 @@ struct v4l2_hevc_enc_ref {
  * @frame_rc_enable: V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE
  * @qp_min: V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP
  * @qp_max: V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP
+ * @qp_min_i: V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_MIN_QP, @qp_min if the driver
+ *	      has no such control. Limits the I pictures with a frame rate
+ *	      control instead of @qp_min.
+ * @qp_max_i: V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_MAX_QP, @qp_max if the driver
+ *	      has no such control
  * @qp_i: V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_QP
  * @qp_p: V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_QP
  * @qp_b: V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_QP
@@ -153,6 +158,8 @@ struct v4l2_hevc_enc_state {
 	bool frame_rc_enable;
 	int qp_min;
 	int qp_max;
+	int qp_min_i;
+	int qp_max_i;
 	int qp_i;
 	int qp_p;
 	int qp_b;

-- 
2.55.0


WARNING: multiple messages have this Message-ID (diff)
From: Arun Iyengar via B4 Relay <devnull+aiyengar1990.gmail.com@kernel.org>
To: Mauro Carvalho Chehab <mchehab@kernel.org>
Cc: linux-media@vger.kernel.org, linux-kernel@vger.kernel.org,
	 Paul Kocialkowski <paulk@sys-base.io>,
	 Nicolas Dufresne <nicolas.dufresne@collabora.com>,
	 Hans Verkuil <hverkuil@kernel.org>,
	Arun Iyengar <aiyengar1990@gmail.com>
Subject: [PATCH RFC 08/10] media: v4l2-hevc-enc: Add QP limits for the I pictures
Date: Tue, 10 Nov 2026 10:07:38 +0000	[thread overview]
Message-ID: <20261110-hevc-encode-uapi-v1-8-38ae9fcfedd4@gmail.com> (raw)
In-Reply-To: <20261110-hevc-encode-uapi-v1-0-38ae9fcfedd4@gmail.com>

From: Arun Iyengar <aiyengar1990@gmail.com>

The frame rate control of the core limits all pictures to the range of
V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP and V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP. The
I pictures, coded several QP steps below the P pictures, then reach very
low QP values at high bitrates, where they cost many bits for little
quality.

Take the limits of the I pictures from V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_MIN_QP
and V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_MAX_QP when the driver has them, with
a frame rate control. Without these controls, nothing changes.

Signed-off-by: Arun Iyengar <aiyengar1990@gmail.com>
---
 drivers/media/v4l2-core/v4l2-hevc-enc.c | 24 +++++++++++++++++++++---
 include/media/v4l2-hevc-enc.h           |  7 +++++++
 2 files changed, 28 insertions(+), 3 deletions(-)

diff --git a/drivers/media/v4l2-core/v4l2-hevc-enc.c b/drivers/media/v4l2-core/v4l2-hevc-enc.c
index a167c4af6288..2e0ba832b868 100644
--- a/drivers/media/v4l2-core/v4l2-hevc-enc.c
+++ b/drivers/media/v4l2-core/v4l2-hevc-enc.c
@@ -645,6 +645,12 @@ static void prepare_rc(struct v4l2_hevc_enc *enc,
 	state->qp_min = enc_ctrl_val(enc, V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP,
 				     -qp_bd_offset);
 	state->qp_max = enc_ctrl_val(enc, V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP, 51);
+	state->qp_min_i = enc_ctrl_val(enc,
+				       V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_MIN_QP,
+				       state->qp_min);
+	state->qp_max_i = enc_ctrl_val(enc,
+				       V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_MAX_QP,
+				       state->qp_max);
 	state->qp_i = enc_ctrl_val(enc, V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_QP, 30);
 	state->qp_p = enc_ctrl_val(enc, V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_QP,
 				   state->qp_i);
@@ -1072,10 +1078,23 @@ static bool rc_core_cbr(const struct v4l2_hevc_enc *enc,
 	       !(enc->rc_ops && enc->rc_ops->estimate);
 }
 
+/* QP limits of the picture: the I picture ones with a frame rate control */
+static int rc_clamp_qp(const struct v4l2_hevc_enc_state *state, int qp)
+{
+	int qp_bd_offset = 6 * state->sps.bit_depth_luma_minus8;
+
+	if (state->frame_rc_enable &&
+	    state->encode.slice_type == V4L2_HEVC_SLICE_TYPE_I)
+		qp = clamp(qp, state->qp_min_i, state->qp_max_i);
+	else
+		qp = clamp(qp, state->qp_min, state->qp_max);
+
+	return clamp(qp, -qp_bd_offset, 51);
+}
+
 static int rc_step(struct v4l2_hevc_enc *enc)
 {
 	struct v4l2_hevc_enc_state *state = &enc->state_active;
-	int qp_bd_offset = 6 * state->sps.bit_depth_luma_minus8;
 	u8 slice_type = state->encode.slice_type;
 	unsigned int range;
 	int qp, ret;
@@ -1114,8 +1133,7 @@ static int rc_step(struct v4l2_hevc_enc *enc)
 			return ret;
 	}
 
-	qp = clamp(qp, state->qp_min, state->qp_max);
-	enc->qp = clamp(qp, -qp_bd_offset, 51);
+	enc->qp = rc_clamp_qp(state, qp);
 
 	return 0;
 }
diff --git a/include/media/v4l2-hevc-enc.h b/include/media/v4l2-hevc-enc.h
index 3db131370c56..f1d3da3269f1 100644
--- a/include/media/v4l2-hevc-enc.h
+++ b/include/media/v4l2-hevc-enc.h
@@ -128,6 +128,11 @@ struct v4l2_hevc_enc_ref {
  * @frame_rc_enable: V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE
  * @qp_min: V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP
  * @qp_max: V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP
+ * @qp_min_i: V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_MIN_QP, @qp_min if the driver
+ *	      has no such control. Limits the I pictures with a frame rate
+ *	      control instead of @qp_min.
+ * @qp_max_i: V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_MAX_QP, @qp_max if the driver
+ *	      has no such control
  * @qp_i: V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_QP
  * @qp_p: V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_QP
  * @qp_b: V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_QP
@@ -153,6 +158,8 @@ struct v4l2_hevc_enc_state {
 	bool frame_rc_enable;
 	int qp_min;
 	int qp_max;
+	int qp_min_i;
+	int qp_max_i;
 	int qp_i;
 	int qp_p;
 	int qp_b;

-- 
2.55.0



  parent reply	other threads:[~2026-11-10 10:07 UTC|newest]

Thread overview: 22+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-10 10:07 [PATCH RFC 00/10] media: Add a V4L2 HEVC stateless encode uAPI and helpers Arun Iyengar
2026-11-10 10:07 ` Arun Iyengar via B4 Relay
2026-11-10 10:07 ` [PATCH RFC 01/10] media: hevc: Add H.265 syntax definitions Arun Iyengar
2026-11-10 10:07   ` Arun Iyengar via B4 Relay
2026-11-10 10:07 ` [PATCH RFC 02/10] media: uapi: Add HEVC stateless encode support Arun Iyengar
2026-11-10 10:07   ` Arun Iyengar via B4 Relay
2026-11-10 10:07 ` [PATCH RFC 03/10] media: hevc: Add stateless encode RBSP writer Arun Iyengar
2026-11-10 10:07   ` Arun Iyengar via B4 Relay
2026-11-10 10:07 ` [PATCH RFC 04/10] media: hevc: Add KUnit tests for the " Arun Iyengar
2026-11-10 10:07   ` Arun Iyengar via B4 Relay
2026-11-10 10:07 ` [PATCH RFC 05/10] media: hevc: Add stateless encode core Arun Iyengar
2026-11-10 10:07   ` Arun Iyengar via B4 Relay
2026-11-10 10:07 ` [PATCH RFC 06/10] media: hevc: Add KUnit tests for the " Arun Iyengar
2026-11-10 10:07   ` Arun Iyengar via B4 Relay
2026-11-10 10:07 ` [PATCH RFC 07/10] media: v4l2-hevc-enc: Add a constant bitrate mode Arun Iyengar
2026-11-10 10:07   ` Arun Iyengar via B4 Relay
2026-11-10 10:07 ` Arun Iyengar [this message]
2026-11-10 10:07   ` [PATCH RFC 08/10] media: v4l2-hevc-enc: Add QP limits for the I pictures Arun Iyengar via B4 Relay
2026-11-10 10:07 ` [PATCH RFC 09/10] media: v4l2-hevc-enc: Re-encode oversized pictures Arun Iyengar
2026-11-10 10:07   ` Arun Iyengar via B4 Relay
2026-11-10 10:07 ` [PATCH RFC 10/10] media: docs: Document the HEVC stateless encode uAPI Arun Iyengar
2026-11-10 10:07   ` Arun Iyengar via B4 Relay

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20261110-hevc-encode-uapi-v1-8-38ae9fcfedd4@gmail.com \
    --to=aiyengar1990@gmail.com \
    --cc=hverkuil@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-media@vger.kernel.org \
    --cc=mchehab@kernel.org \
    --cc=nicolas.dufresne@collabora.com \
    --cc=paulk@sys-base.io \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.