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 03/10] media: hevc: Add stateless encode RBSP writer
Date: Tue, 10 Nov 2026 10:07:33 +0000 [thread overview]
Message-ID: <20261110-hevc-encode-uapi-v1-3-38ae9fcfedd4@gmail.com> (raw)
In-Reply-To: <20261110-hevc-encode-uapi-v1-0-38ae9fcfedd4@gmail.com>
From: Arun Iyengar <aiyengar1990@gmail.com>
Add a writer for the HEVC NAL units that a stateless encoder needs the
kernel to produce: video, sequence and picture parameter sets, access
unit delimiters and slice segment headers, with optional Annex B start
codes. It is the HEVC counterpart of the H.264 stateless encode RBSP
helper.
The SPS and PPS are written from the existing struct v4l2_ctrl_hevc_sps
and struct v4l2_ctrl_hevc_pps. What those structures do not carry
because a decoder does not need it (profile, tier and level, the
conformance window, VUI, temporal nesting) comes from a kernel-internal
struct v4l2_hevc_sps_video, like struct v4l2_h264_sps_video does for
H.264. The VPS is derived from both. Slice segment headers are written
from a struct v4l2_hevc_slice_header holding the resolved syntax element
values, so that drivers for hardware that writes its own slice headers
can program their registers from the same structure.
The scope is what an encoder chooses to use: reference picture sets are
always coded in the slice header, the SPS carries no RPS and no
long-term reference pictures, scaling lists are the default ones,
reference picture lists are not modified and there are no weighted
prediction tables, HRD parameters, SEI or extensions. Writing those
returns -EINVAL rather than an incorrect bitstream.
Emulation prevention is applied byte by byte as the payload is written,
and errors (a full buffer, values that cannot be coded) are sticky so
that the syntax writers read like the syntax tables of the
specification. The H.264 writer keeps its own bit writer for now; both
could share one later.
Signed-off-by: Arun Iyengar <aiyengar1990@gmail.com>
---
drivers/media/v4l2-core/Kconfig | 4 +
drivers/media/v4l2-core/Makefile | 1 +
drivers/media/v4l2-core/v4l2-hevc-enc-rbsp.c | 977 +++++++++++++++++++++++++++
include/media/v4l2-hevc-enc-rbsp.h | 279 ++++++++
4 files changed, 1261 insertions(+)
diff --git a/drivers/media/v4l2-core/Kconfig b/drivers/media/v4l2-core/Kconfig
index b8b849a44abd..9f9eda5d6eac 100644
--- a/drivers/media/v4l2-core/Kconfig
+++ b/drivers/media/v4l2-core/Kconfig
@@ -53,6 +53,10 @@ config V4L2_H264_ENC
tristate
select V4L2_ENC_CBR
+# Used by drivers that need v4l2-hevc-enc-rbsp.ko
+config V4L2_HEVC_ENC_RBSP
+ tristate
+
# Used by drivers that need v4l2-vp9.ko
config V4L2_VP9
tristate
diff --git a/drivers/media/v4l2-core/Makefile b/drivers/media/v4l2-core/Makefile
index 3aa0855d7be7..3dda145d94d1 100644
--- a/drivers/media/v4l2-core/Makefile
+++ b/drivers/media/v4l2-core/Makefile
@@ -32,6 +32,7 @@ obj-$(CONFIG_V4L2_FWNODE) += v4l2-fwnode.o
obj-$(CONFIG_V4L2_H264) += v4l2-h264.o
obj-$(CONFIG_V4L2_H264_ENC) += v4l2-h264-enc.o v4l2-h264-enc-rbsp.o \
v4l2-h264-enc-rc.o
+obj-$(CONFIG_V4L2_HEVC_ENC_RBSP) += v4l2-hevc-enc-rbsp.o
obj-$(CONFIG_V4L2_ISP) += v4l2-isp.o
obj-$(CONFIG_V4L2_JPEG_HELPER) += v4l2-jpeg.o
obj-$(CONFIG_V4L2_MEM2MEM_DEV) += v4l2-mem2mem.o
diff --git a/drivers/media/v4l2-core/v4l2-hevc-enc-rbsp.c b/drivers/media/v4l2-core/v4l2-hevc-enc-rbsp.c
new file mode 100644
index 000000000000..ee9242f92950
--- /dev/null
+++ b/drivers/media/v4l2-core/v4l2-hevc-enc-rbsp.c
@@ -0,0 +1,977 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * V4L2 HEVC Encode RBSP
+ *
+ * Section and table numbers refer to ITU-T Rec. H.265 (V10, 07/2024).
+ */
+
+#include <linux/bitops.h>
+#include <linux/bits.h>
+#include <linux/bug.h>
+#include <linux/errno.h>
+#include <linux/export.h>
+#include <linux/limits.h>
+#include <linux/log2.h>
+#include <linux/math.h>
+#include <linux/minmax.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/v4l2-controls.h>
+#include <media/v4l2-hevc.h>
+#include <media/v4l2-hevc-enc-rbsp.h>
+
+#define EMULATION_PREVENTION_THREE_BYTE 0x03
+
+/**
+ * v4l2_hevc_enc_rbsp_init() - start writing NAL units to a buffer
+ * @rbsp: the writer
+ * @data: the destination buffer
+ * @size: the size of @data in bytes
+ */
+void v4l2_hevc_enc_rbsp_init(struct v4l2_hevc_enc_rbsp *rbsp, u8 *data,
+ unsigned int size)
+{
+ memset(rbsp, 0, sizeof(*rbsp));
+ rbsp->data = data;
+ rbsp->size = size;
+}
+EXPORT_SYMBOL_GPL(v4l2_hevc_enc_rbsp_init);
+
+/**
+ * v4l2_hevc_enc_rbsp_bytes() - number of bytes written so far
+ * @rbsp: the writer
+ *
+ * Bits that do not fill a byte yet are not counted. All the NAL unit and
+ * slice header writers end byte-aligned.
+ *
+ * Return: the number of bytes written, emulation prevention bytes included.
+ */
+unsigned int v4l2_hevc_enc_rbsp_bytes(const struct v4l2_hevc_enc_rbsp *rbsp)
+{
+ return rbsp->offset;
+}
+EXPORT_SYMBOL_GPL(v4l2_hevc_enc_rbsp_bytes);
+
+/**
+ * v4l2_hevc_enc_rbsp_error() - first error of the writer
+ * @rbsp: the writer
+ *
+ * Return: 0, -ENOSPC when the buffer is too small, or -EINVAL when a value
+ * cannot be represented or the parameters are not supported.
+ */
+int v4l2_hevc_enc_rbsp_error(const struct v4l2_hevc_enc_rbsp *rbsp)
+{
+ return rbsp->error;
+}
+EXPORT_SYMBOL_GPL(v4l2_hevc_enc_rbsp_error);
+
+static void rbsp_fail(struct v4l2_hevc_enc_rbsp *rbsp, int error)
+{
+ if (!rbsp->error)
+ rbsp->error = error;
+}
+
+static void rbsp_emit(struct v4l2_hevc_enc_rbsp *rbsp, u8 byte)
+{
+ if (rbsp->offset >= rbsp->size) {
+ rbsp_fail(rbsp, -ENOSPC);
+ return;
+ }
+
+ rbsp->data[rbsp->offset++] = byte;
+}
+
+/*
+ * Write one byte of a NAL unit. Inside the payload, a byte in the range
+ * 0x00 to 0x03 that follows two zero bytes gets an
+ * emulation_prevention_three_byte in front of it (7.4.2).
+ */
+static void rbsp_put_byte(struct v4l2_hevc_enc_rbsp *rbsp, u8 byte)
+{
+ if (rbsp->error)
+ return;
+
+ if (rbsp->epb && rbsp->zero_bytes >= 2 &&
+ byte <= EMULATION_PREVENTION_THREE_BYTE) {
+ rbsp_emit(rbsp, EMULATION_PREVENTION_THREE_BYTE);
+ rbsp->zero_bytes = 0;
+ }
+
+ rbsp_emit(rbsp, byte);
+
+ if (byte)
+ rbsp->zero_bytes = 0;
+ else
+ rbsp->zero_bytes++;
+}
+
+/**
+ * v4l2_hevc_enc_rbsp_bits() - write a fixed-length value, u(n)
+ * @rbsp: the writer
+ * @value: the value, only the @count low bits are written
+ * @count: the number of bits, up to 32
+ */
+void v4l2_hevc_enc_rbsp_bits(struct v4l2_hevc_enc_rbsp *rbsp, u32 value,
+ unsigned int count)
+{
+ if (rbsp->error || !count)
+ return;
+
+ if (WARN_ON(count > 32)) {
+ rbsp_fail(rbsp, -EINVAL);
+ return;
+ }
+
+ rbsp->cache = (rbsp->cache << count) | (value & GENMASK(count - 1, 0));
+ rbsp->cache_bits += count;
+
+ while (rbsp->cache_bits >= 8) {
+ rbsp->cache_bits -= 8;
+ rbsp_put_byte(rbsp, rbsp->cache >> rbsp->cache_bits);
+ }
+
+ rbsp->cache &= GENMASK_ULL(7, 0) >> (8 - rbsp->cache_bits);
+}
+EXPORT_SYMBOL_GPL(v4l2_hevc_enc_rbsp_bits);
+
+static void rbsp_flag(struct v4l2_hevc_enc_rbsp *rbsp, bool value)
+{
+ v4l2_hevc_enc_rbsp_bits(rbsp, value, 1);
+}
+
+static void rbsp_flags(struct v4l2_hevc_enc_rbsp *rbsp, u64 flags, u64 flag)
+{
+ rbsp_flag(rbsp, !!(flags & flag));
+}
+
+/**
+ * v4l2_hevc_enc_rbsp_ue() - write an unsigned Exp-Golomb value, ue(v) (9.2)
+ * @rbsp: the writer
+ * @value: the value, up to 2^32 - 2
+ */
+void v4l2_hevc_enc_rbsp_ue(struct v4l2_hevc_enc_rbsp *rbsp, u32 value)
+{
+ u64 code = (u64)value + 1;
+ unsigned int len = fls64(code);
+
+ if (value == U32_MAX) {
+ rbsp_fail(rbsp, -EINVAL);
+ return;
+ }
+
+ /* len - 1 leading zero bits, then code on len bits. */
+ v4l2_hevc_enc_rbsp_bits(rbsp, 0, len - 1);
+ v4l2_hevc_enc_rbsp_bits(rbsp, code, len);
+}
+EXPORT_SYMBOL_GPL(v4l2_hevc_enc_rbsp_ue);
+
+/**
+ * v4l2_hevc_enc_rbsp_se() - write a signed Exp-Golomb value, se(v) (9.2.2)
+ * @rbsp: the writer
+ * @value: the value, from -(2^31 - 1) to 2^31 - 1
+ */
+void v4l2_hevc_enc_rbsp_se(struct v4l2_hevc_enc_rbsp *rbsp, s32 value)
+{
+ if (value == S32_MIN) {
+ rbsp_fail(rbsp, -EINVAL);
+ return;
+ }
+
+ if (value > 0)
+ v4l2_hevc_enc_rbsp_ue(rbsp, 2 * (u32)value - 1);
+ else
+ v4l2_hevc_enc_rbsp_ue(rbsp, 2 * (u32)-value);
+}
+EXPORT_SYMBOL_GPL(v4l2_hevc_enc_rbsp_se);
+
+/**
+ * v4l2_hevc_enc_rbsp_trailing_bits() - write rbsp_trailing_bits() (7.3.2.11)
+ * @rbsp: the writer
+ *
+ * A one bit followed by zero bits up to the next byte boundary. This is
+ * also the bit pattern of byte_alignment() (7.3.2.12), which ends slice
+ * segment headers.
+ */
+void v4l2_hevc_enc_rbsp_trailing_bits(struct v4l2_hevc_enc_rbsp *rbsp)
+{
+ rbsp_flag(rbsp, 1);
+
+ if (rbsp->cache_bits)
+ v4l2_hevc_enc_rbsp_bits(rbsp, 0, 8 - rbsp->cache_bits);
+}
+EXPORT_SYMBOL_GPL(v4l2_hevc_enc_rbsp_trailing_bits);
+
+/**
+ * v4l2_hevc_enc_rbsp_nal_begin() - start a NAL unit
+ * @rbsp: the writer
+ * @start_code: whether to write an Annex B start code (with zero_byte)
+ * @nal_unit_type: nal_unit_type
+ * @nuh_temporal_id_plus1: nuh_temporal_id_plus1
+ *
+ * Writes the optional start code and the NAL unit header (7.3.1.2), with
+ * nuh_layer_id equal to 0, then enables emulation prevention for the
+ * payload.
+ */
+void v4l2_hevc_enc_rbsp_nal_begin(struct v4l2_hevc_enc_rbsp *rbsp,
+ bool start_code, u8 nal_unit_type,
+ u8 nuh_temporal_id_plus1)
+{
+ if (WARN_ON(rbsp->cache_bits) || nal_unit_type > 63 ||
+ !nuh_temporal_id_plus1 || nuh_temporal_id_plus1 > 7) {
+ rbsp_fail(rbsp, -EINVAL);
+ return;
+ }
+
+ rbsp->epb = false;
+
+ if (start_code)
+ v4l2_hevc_enc_rbsp_bits(rbsp, 0x00000001, 32);
+
+ /* forbidden_zero_bit, nal_unit_type, nuh_layer_id */
+ v4l2_hevc_enc_rbsp_bits(rbsp, nal_unit_type << 1, 8);
+ v4l2_hevc_enc_rbsp_bits(rbsp, nuh_temporal_id_plus1, 8);
+
+ rbsp->epb = true;
+ rbsp->zero_bytes = 0;
+}
+EXPORT_SYMBOL_GPL(v4l2_hevc_enc_rbsp_nal_begin);
+
+/**
+ * v4l2_hevc_enc_rbsp_nal_end() - end a NAL unit with rbsp_trailing_bits()
+ * @rbsp: the writer
+ */
+void v4l2_hevc_enc_rbsp_nal_end(struct v4l2_hevc_enc_rbsp *rbsp)
+{
+ v4l2_hevc_enc_rbsp_trailing_bits(rbsp);
+ rbsp->epb = false;
+}
+EXPORT_SYMBOL_GPL(v4l2_hevc_enc_rbsp_nal_end);
+
+/**
+ * v4l2_hevc_enc_rbsp_aud() - write an access unit delimiter (7.3.2.5)
+ * @rbsp: the writer
+ * @start_code: whether to write an Annex B start code
+ * @pic_type: pic_type, see V4L2_HEVC_AUD_PIC_TYPE_{}
+ * @nuh_temporal_id_plus1: TemporalId of the access unit, plus 1
+ *
+ * Return: 0 or the first error of the writer.
+ */
+int v4l2_hevc_enc_rbsp_aud(struct v4l2_hevc_enc_rbsp *rbsp, bool start_code,
+ u8 pic_type, u8 nuh_temporal_id_plus1)
+{
+ if (pic_type > V4L2_HEVC_AUD_PIC_TYPE_BPI)
+ rbsp_fail(rbsp, -EINVAL);
+
+ v4l2_hevc_enc_rbsp_nal_begin(rbsp, start_code, V4L2_HEVC_NAL_AUD,
+ nuh_temporal_id_plus1);
+ v4l2_hevc_enc_rbsp_bits(rbsp, pic_type, 3);
+ v4l2_hevc_enc_rbsp_nal_end(rbsp);
+
+ return rbsp->error;
+}
+EXPORT_SYMBOL_GPL(v4l2_hevc_enc_rbsp_aud);
+
+/* profile_tier_level(1, max_sub_layers_minus1) (7.3.3) */
+static void rbsp_ptl(struct v4l2_hevc_enc_rbsp *rbsp,
+ const struct v4l2_hevc_ptl *ptl,
+ unsigned int max_sub_layers_minus1)
+{
+ unsigned int i;
+
+ v4l2_hevc_enc_rbsp_bits(rbsp, ptl->general_profile_space, 2);
+ rbsp_flag(rbsp, ptl->general_tier_flag);
+ v4l2_hevc_enc_rbsp_bits(rbsp, ptl->general_profile_idc, 5);
+ v4l2_hevc_enc_rbsp_bits(rbsp, ptl->general_profile_compatibility_flags,
+ 32);
+ rbsp_flags(rbsp, ptl->flags, V4L2_HEVC_PTL_FLAG_PROGRESSIVE_SOURCE);
+ rbsp_flags(rbsp, ptl->flags, V4L2_HEVC_PTL_FLAG_INTERLACED_SOURCE);
+ rbsp_flags(rbsp, ptl->flags, V4L2_HEVC_PTL_FLAG_NON_PACKED_CONSTRAINT);
+ rbsp_flags(rbsp, ptl->flags, V4L2_HEVC_PTL_FLAG_FRAME_ONLY_CONSTRAINT);
+
+ /*
+ * The 43 bits of general_reserved_zero_43bits, or of the format range
+ * extensions constraint flags which are all 0 for the profiles that
+ * can be signalled, then general_inbld_flag or
+ * general_reserved_zero_bit.
+ */
+ v4l2_hevc_enc_rbsp_bits(rbsp, 0, 32);
+ v4l2_hevc_enc_rbsp_bits(rbsp, 0, 11);
+ v4l2_hevc_enc_rbsp_bits(rbsp, 0, 1);
+
+ v4l2_hevc_enc_rbsp_bits(rbsp, ptl->general_level_idc, 8);
+
+ /* sub_layer_profile_present_flag and sub_layer_level_present_flag */
+ for (i = 0; i < max_sub_layers_minus1; i++)
+ v4l2_hevc_enc_rbsp_bits(rbsp, 0, 2);
+
+ /* reserved_zero_2bits */
+ if (max_sub_layers_minus1)
+ for (i = max_sub_layers_minus1; i < 8; i++)
+ v4l2_hevc_enc_rbsp_bits(rbsp, 0, 2);
+}
+
+/*
+ * The sub-layer ordering info is written once, for the highest sub-layer,
+ * when there are several sub-layers: the lower ones infer the same values.
+ * With a single sub-layer, sub_layer_ordering_info_present_flag is set like
+ * common encoders do; the bits are the same apart from the flag.
+ */
+static void rbsp_sub_layer_ordering(struct v4l2_hevc_enc_rbsp *rbsp,
+ const struct v4l2_ctrl_hevc_sps *sps)
+{
+ rbsp_flag(rbsp, !sps->sps_max_sub_layers_minus1);
+ v4l2_hevc_enc_rbsp_ue(rbsp, sps->sps_max_dec_pic_buffering_minus1);
+ v4l2_hevc_enc_rbsp_ue(rbsp, sps->sps_max_num_reorder_pics);
+ v4l2_hevc_enc_rbsp_ue(rbsp, sps->sps_max_latency_increase_plus1);
+}
+
+static void rbsp_timing_info(struct v4l2_hevc_enc_rbsp *rbsp,
+ const struct v4l2_hevc_sps_video *video)
+{
+ bool poc_proportional = video->flags &
+ V4L2_HEVC_SPS_VIDEO_FLAG_VUI_POC_PROPORTIONAL_TO_TIMING;
+
+ v4l2_hevc_enc_rbsp_bits(rbsp, video->num_units_in_tick, 32);
+ v4l2_hevc_enc_rbsp_bits(rbsp, video->time_scale, 32);
+ rbsp_flag(rbsp, poc_proportional);
+ if (poc_proportional)
+ v4l2_hevc_enc_rbsp_ue(rbsp,
+ video->num_ticks_poc_diff_one_minus1);
+}
+
+/**
+ * v4l2_hevc_enc_rbsp_vps() - write a video parameter set (7.3.2.1)
+ * @rbsp: the writer
+ * @start_code: whether to write an Annex B start code
+ * @sps: the SPS the VPS describes
+ * @sps_video: the VPS/SPS fields not in @sps
+ *
+ * The VPS describes a single layer with the sub-layers of @sps and no HRD
+ * parameters.
+ *
+ * Return: 0 or the first error of the writer.
+ */
+int v4l2_hevc_enc_rbsp_vps(struct v4l2_hevc_enc_rbsp *rbsp, bool start_code,
+ const struct v4l2_ctrl_hevc_sps *sps,
+ const struct v4l2_hevc_sps_video *sps_video)
+{
+ u32 flags = sps_video->flags;
+ bool timing = flags & V4L2_HEVC_SPS_VIDEO_FLAG_VPS_TIMING_INFO_PRESENT;
+
+ if (sps->video_parameter_set_id > 15 ||
+ sps->sps_max_sub_layers_minus1 >= V4L2_HEVC_MAX_SUB_LAYERS)
+ rbsp_fail(rbsp, -EINVAL);
+
+ v4l2_hevc_enc_rbsp_nal_begin(rbsp, start_code, V4L2_HEVC_NAL_VPS, 1);
+
+ v4l2_hevc_enc_rbsp_bits(rbsp, sps->video_parameter_set_id, 4);
+ rbsp_flag(rbsp, 1); /* vps_base_layer_internal_flag */
+ rbsp_flag(rbsp, 1); /* vps_base_layer_available_flag */
+ v4l2_hevc_enc_rbsp_bits(rbsp, 0, 6); /* vps_max_layers_minus1 */
+ v4l2_hevc_enc_rbsp_bits(rbsp, sps->sps_max_sub_layers_minus1, 3);
+ rbsp_flags(rbsp, flags, V4L2_HEVC_SPS_VIDEO_FLAG_TEMPORAL_ID_NESTING);
+ v4l2_hevc_enc_rbsp_bits(rbsp, 0xffff, 16); /* vps_reserved_0xffff_16bits */
+
+ rbsp_ptl(rbsp, &sps_video->ptl, sps->sps_max_sub_layers_minus1);
+ rbsp_sub_layer_ordering(rbsp, sps);
+
+ v4l2_hevc_enc_rbsp_bits(rbsp, 0, 6); /* vps_max_layer_id */
+ v4l2_hevc_enc_rbsp_ue(rbsp, 0); /* vps_num_layer_sets_minus1 */
+
+ rbsp_flag(rbsp, timing);
+ if (timing) {
+ rbsp_timing_info(rbsp, sps_video);
+ v4l2_hevc_enc_rbsp_ue(rbsp, 0); /* vps_num_hrd_parameters */
+ }
+
+ rbsp_flag(rbsp, 0); /* vps_extension_flag */
+
+ v4l2_hevc_enc_rbsp_nal_end(rbsp);
+
+ return rbsp->error;
+}
+EXPORT_SYMBOL_GPL(v4l2_hevc_enc_rbsp_vps);
+
+/* vui_parameters() (E.2.1), without HRD parameters */
+static void rbsp_vui(struct v4l2_hevc_enc_rbsp *rbsp,
+ const struct v4l2_hevc_sps_video *video)
+{
+ u32 flags = video->flags;
+
+ rbsp_flags(rbsp, flags,
+ V4L2_HEVC_SPS_VIDEO_FLAG_VUI_ASPECT_RATIO_INFO_PRESENT);
+ if (flags & V4L2_HEVC_SPS_VIDEO_FLAG_VUI_ASPECT_RATIO_INFO_PRESENT) {
+ v4l2_hevc_enc_rbsp_bits(rbsp, video->aspect_ratio_idc, 8);
+ if (video->aspect_ratio_idc ==
+ V4L2_HEVC_VUI_ASPECT_RATIO_IDC_EXTENDED) {
+ v4l2_hevc_enc_rbsp_bits(rbsp, video->sar_width, 16);
+ v4l2_hevc_enc_rbsp_bits(rbsp, video->sar_height, 16);
+ }
+ }
+
+ rbsp_flags(rbsp, flags,
+ V4L2_HEVC_SPS_VIDEO_FLAG_VUI_OVERSCAN_INFO_PRESENT);
+ if (flags & V4L2_HEVC_SPS_VIDEO_FLAG_VUI_OVERSCAN_INFO_PRESENT)
+ rbsp_flags(rbsp, flags,
+ V4L2_HEVC_SPS_VIDEO_FLAG_VUI_OVERSCAN_APPROPRIATE);
+
+ rbsp_flags(rbsp, flags,
+ V4L2_HEVC_SPS_VIDEO_FLAG_VUI_VIDEO_SIGNAL_TYPE_PRESENT);
+ if (flags & V4L2_HEVC_SPS_VIDEO_FLAG_VUI_VIDEO_SIGNAL_TYPE_PRESENT) {
+ v4l2_hevc_enc_rbsp_bits(rbsp, video->video_format, 3);
+ rbsp_flags(rbsp, flags,
+ V4L2_HEVC_SPS_VIDEO_FLAG_VUI_VIDEO_FULL_RANGE);
+ rbsp_flags(rbsp, flags,
+ V4L2_HEVC_SPS_VIDEO_FLAG_VUI_COLOUR_DESCRIPTION_PRESENT);
+ if (flags &
+ V4L2_HEVC_SPS_VIDEO_FLAG_VUI_COLOUR_DESCRIPTION_PRESENT) {
+ v4l2_hevc_enc_rbsp_bits(rbsp, video->colour_primaries,
+ 8);
+ v4l2_hevc_enc_rbsp_bits(rbsp,
+ video->transfer_characteristics,
+ 8);
+ v4l2_hevc_enc_rbsp_bits(rbsp, video->matrix_coeffs, 8);
+ }
+ }
+
+ rbsp_flags(rbsp, flags,
+ V4L2_HEVC_SPS_VIDEO_FLAG_VUI_CHROMA_LOC_INFO_PRESENT);
+ if (flags & V4L2_HEVC_SPS_VIDEO_FLAG_VUI_CHROMA_LOC_INFO_PRESENT) {
+ v4l2_hevc_enc_rbsp_ue(rbsp,
+ video->chroma_sample_loc_type_top_field);
+ v4l2_hevc_enc_rbsp_ue(rbsp,
+ video->chroma_sample_loc_type_bottom_field);
+ }
+
+ rbsp_flag(rbsp, 0); /* neutral_chroma_indication_flag */
+ rbsp_flag(rbsp, 0); /* field_seq_flag */
+ rbsp_flag(rbsp, 0); /* frame_field_info_present_flag */
+ rbsp_flag(rbsp, 0); /* default_display_window_flag */
+
+ rbsp_flags(rbsp, flags, V4L2_HEVC_SPS_VIDEO_FLAG_VUI_TIMING_INFO_PRESENT);
+ if (flags & V4L2_HEVC_SPS_VIDEO_FLAG_VUI_TIMING_INFO_PRESENT) {
+ rbsp_timing_info(rbsp, video);
+ rbsp_flag(rbsp, 0); /* vui_hrd_parameters_present_flag */
+ }
+
+ rbsp_flags(rbsp, flags, V4L2_HEVC_SPS_VIDEO_FLAG_VUI_BITSTREAM_RESTRICTION);
+ if (flags & V4L2_HEVC_SPS_VIDEO_FLAG_VUI_BITSTREAM_RESTRICTION) {
+ rbsp_flags(rbsp, flags,
+ V4L2_HEVC_SPS_VIDEO_FLAG_VUI_TILES_FIXED_STRUCTURE);
+ rbsp_flags(rbsp, flags,
+ V4L2_HEVC_SPS_VIDEO_FLAG_VUI_MOTION_VECTORS_OVER_PIC_BOUNDARIES);
+ rbsp_flags(rbsp, flags,
+ V4L2_HEVC_SPS_VIDEO_FLAG_VUI_RESTRICTED_REF_PIC_LISTS);
+ v4l2_hevc_enc_rbsp_ue(rbsp, video->min_spatial_segmentation_idc);
+ v4l2_hevc_enc_rbsp_ue(rbsp, video->max_bytes_per_pic_denom);
+ v4l2_hevc_enc_rbsp_ue(rbsp, video->max_bits_per_min_cu_denom);
+ v4l2_hevc_enc_rbsp_ue(rbsp,
+ video->log2_max_mv_length_horizontal);
+ v4l2_hevc_enc_rbsp_ue(rbsp, video->log2_max_mv_length_vertical);
+ }
+}
+
+/**
+ * v4l2_hevc_enc_rbsp_sps() - write a sequence parameter set (7.3.2.2)
+ * @rbsp: the writer
+ * @start_code: whether to write an Annex B start code
+ * @sps: the SPS
+ * @sps_video: the VPS/SPS fields not in @sps
+ *
+ * Short-term reference picture sets and long-term reference pictures
+ * cannot be signalled in the SPS (num_short_term_ref_pic_sets and
+ * num_long_term_ref_pics_sps must be 0), and scaling lists, when enabled,
+ * are the default ones.
+ *
+ * Return: 0 or the first error of the writer.
+ */
+int v4l2_hevc_enc_rbsp_sps(struct v4l2_hevc_enc_rbsp *rbsp, bool start_code,
+ const struct v4l2_ctrl_hevc_sps *sps,
+ const struct v4l2_hevc_sps_video *sps_video)
+{
+ u64 flags = sps->flags;
+ bool conformance_window = sps_video->flags &
+ V4L2_HEVC_SPS_VIDEO_FLAG_CONFORMANCE_WINDOW;
+ bool vui = sps_video->flags &
+ V4L2_HEVC_SPS_VIDEO_FLAG_VUI_PARAMETERS_PRESENT;
+
+ if (sps->video_parameter_set_id > 15 ||
+ sps->seq_parameter_set_id > 15 ||
+ sps->sps_max_sub_layers_minus1 >= V4L2_HEVC_MAX_SUB_LAYERS ||
+ sps->chroma_format_idc > 3 ||
+ sps->num_short_term_ref_pic_sets ||
+ sps->num_long_term_ref_pics_sps)
+ rbsp_fail(rbsp, -EINVAL);
+
+ v4l2_hevc_enc_rbsp_nal_begin(rbsp, start_code, V4L2_HEVC_NAL_SPS, 1);
+
+ v4l2_hevc_enc_rbsp_bits(rbsp, sps->video_parameter_set_id, 4);
+ v4l2_hevc_enc_rbsp_bits(rbsp, sps->sps_max_sub_layers_minus1, 3);
+ rbsp_flags(rbsp, sps_video->flags,
+ V4L2_HEVC_SPS_VIDEO_FLAG_TEMPORAL_ID_NESTING);
+ rbsp_ptl(rbsp, &sps_video->ptl, sps->sps_max_sub_layers_minus1);
+
+ v4l2_hevc_enc_rbsp_ue(rbsp, sps->seq_parameter_set_id);
+ v4l2_hevc_enc_rbsp_ue(rbsp, sps->chroma_format_idc);
+ if (sps->chroma_format_idc == 3)
+ rbsp_flags(rbsp, flags, V4L2_HEVC_SPS_FLAG_SEPARATE_COLOUR_PLANE);
+ v4l2_hevc_enc_rbsp_ue(rbsp, sps->pic_width_in_luma_samples);
+ v4l2_hevc_enc_rbsp_ue(rbsp, sps->pic_height_in_luma_samples);
+
+ rbsp_flag(rbsp, conformance_window);
+ if (conformance_window) {
+ v4l2_hevc_enc_rbsp_ue(rbsp, sps_video->conf_win_left_offset);
+ v4l2_hevc_enc_rbsp_ue(rbsp, sps_video->conf_win_right_offset);
+ v4l2_hevc_enc_rbsp_ue(rbsp, sps_video->conf_win_top_offset);
+ v4l2_hevc_enc_rbsp_ue(rbsp, sps_video->conf_win_bottom_offset);
+ }
+
+ v4l2_hevc_enc_rbsp_ue(rbsp, sps->bit_depth_luma_minus8);
+ v4l2_hevc_enc_rbsp_ue(rbsp, sps->bit_depth_chroma_minus8);
+ v4l2_hevc_enc_rbsp_ue(rbsp, sps->log2_max_pic_order_cnt_lsb_minus4);
+
+ rbsp_sub_layer_ordering(rbsp, sps);
+
+ v4l2_hevc_enc_rbsp_ue(rbsp, sps->log2_min_luma_coding_block_size_minus3);
+ v4l2_hevc_enc_rbsp_ue(rbsp, sps->log2_diff_max_min_luma_coding_block_size);
+ v4l2_hevc_enc_rbsp_ue(rbsp,
+ sps->log2_min_luma_transform_block_size_minus2);
+ v4l2_hevc_enc_rbsp_ue(rbsp,
+ sps->log2_diff_max_min_luma_transform_block_size);
+ v4l2_hevc_enc_rbsp_ue(rbsp, sps->max_transform_hierarchy_depth_inter);
+ v4l2_hevc_enc_rbsp_ue(rbsp, sps->max_transform_hierarchy_depth_intra);
+
+ rbsp_flags(rbsp, flags, V4L2_HEVC_SPS_FLAG_SCALING_LIST_ENABLED);
+ if (flags & V4L2_HEVC_SPS_FLAG_SCALING_LIST_ENABLED)
+ rbsp_flag(rbsp, 0); /* sps_scaling_list_data_present_flag */
+
+ rbsp_flags(rbsp, flags, V4L2_HEVC_SPS_FLAG_AMP_ENABLED);
+ rbsp_flags(rbsp, flags, V4L2_HEVC_SPS_FLAG_SAMPLE_ADAPTIVE_OFFSET);
+
+ rbsp_flags(rbsp, flags, V4L2_HEVC_SPS_FLAG_PCM_ENABLED);
+ if (flags & V4L2_HEVC_SPS_FLAG_PCM_ENABLED) {
+ v4l2_hevc_enc_rbsp_bits(rbsp,
+ sps->pcm_sample_bit_depth_luma_minus1,
+ 4);
+ v4l2_hevc_enc_rbsp_bits(rbsp,
+ sps->pcm_sample_bit_depth_chroma_minus1,
+ 4);
+ v4l2_hevc_enc_rbsp_ue(rbsp,
+ sps->log2_min_pcm_luma_coding_block_size_minus3);
+ v4l2_hevc_enc_rbsp_ue(rbsp,
+ sps->log2_diff_max_min_pcm_luma_coding_block_size);
+ rbsp_flags(rbsp, flags,
+ V4L2_HEVC_SPS_FLAG_PCM_LOOP_FILTER_DISABLED);
+ }
+
+ v4l2_hevc_enc_rbsp_ue(rbsp, 0); /* num_short_term_ref_pic_sets */
+
+ rbsp_flags(rbsp, flags, V4L2_HEVC_SPS_FLAG_LONG_TERM_REF_PICS_PRESENT);
+ if (flags & V4L2_HEVC_SPS_FLAG_LONG_TERM_REF_PICS_PRESENT)
+ v4l2_hevc_enc_rbsp_ue(rbsp, 0); /* num_long_term_ref_pics_sps */
+
+ rbsp_flags(rbsp, flags, V4L2_HEVC_SPS_FLAG_SPS_TEMPORAL_MVP_ENABLED);
+ rbsp_flags(rbsp, flags, V4L2_HEVC_SPS_FLAG_STRONG_INTRA_SMOOTHING_ENABLED);
+
+ rbsp_flag(rbsp, vui);
+ if (vui)
+ rbsp_vui(rbsp, sps_video);
+
+ rbsp_flag(rbsp, 0); /* sps_extension_present_flag */
+
+ v4l2_hevc_enc_rbsp_nal_end(rbsp);
+
+ return rbsp->error;
+}
+EXPORT_SYMBOL_GPL(v4l2_hevc_enc_rbsp_sps);
+
+/**
+ * v4l2_hevc_enc_rbsp_pps() - write a picture parameter set (7.3.2.3)
+ * @rbsp: the writer
+ * @start_code: whether to write an Annex B start code
+ * @sps: the SPS the PPS refers to
+ * @pps: the PPS
+ *
+ * Scaling lists are never signalled in the PPS and no PPS extension is
+ * written.
+ *
+ * Return: 0 or the first error of the writer.
+ */
+int v4l2_hevc_enc_rbsp_pps(struct v4l2_hevc_enc_rbsp *rbsp, bool start_code,
+ const struct v4l2_ctrl_hevc_sps *sps,
+ const struct v4l2_ctrl_hevc_pps *pps)
+{
+ u64 flags = pps->flags;
+ unsigned int i;
+
+ if (pps->pic_parameter_set_id > 63 ||
+ pps->num_extra_slice_header_bits > 7 ||
+ (flags & V4L2_HEVC_PPS_FLAG_TILES_ENABLED &&
+ (pps->num_tile_columns_minus1 >=
+ ARRAY_SIZE(pps->column_width_minus1) ||
+ pps->num_tile_rows_minus1 >= ARRAY_SIZE(pps->row_height_minus1))))
+ rbsp_fail(rbsp, -EINVAL);
+
+ v4l2_hevc_enc_rbsp_nal_begin(rbsp, start_code, V4L2_HEVC_NAL_PPS, 1);
+
+ v4l2_hevc_enc_rbsp_ue(rbsp, pps->pic_parameter_set_id);
+ v4l2_hevc_enc_rbsp_ue(rbsp, sps->seq_parameter_set_id);
+ rbsp_flags(rbsp, flags,
+ V4L2_HEVC_PPS_FLAG_DEPENDENT_SLICE_SEGMENT_ENABLED);
+ rbsp_flags(rbsp, flags, V4L2_HEVC_PPS_FLAG_OUTPUT_FLAG_PRESENT);
+ v4l2_hevc_enc_rbsp_bits(rbsp, pps->num_extra_slice_header_bits, 3);
+ rbsp_flags(rbsp, flags, V4L2_HEVC_PPS_FLAG_SIGN_DATA_HIDING_ENABLED);
+ rbsp_flags(rbsp, flags, V4L2_HEVC_PPS_FLAG_CABAC_INIT_PRESENT);
+ v4l2_hevc_enc_rbsp_ue(rbsp, pps->num_ref_idx_l0_default_active_minus1);
+ v4l2_hevc_enc_rbsp_ue(rbsp, pps->num_ref_idx_l1_default_active_minus1);
+ v4l2_hevc_enc_rbsp_se(rbsp, pps->init_qp_minus26);
+ rbsp_flags(rbsp, flags, V4L2_HEVC_PPS_FLAG_CONSTRAINED_INTRA_PRED);
+ rbsp_flags(rbsp, flags, V4L2_HEVC_PPS_FLAG_TRANSFORM_SKIP_ENABLED);
+
+ rbsp_flags(rbsp, flags, V4L2_HEVC_PPS_FLAG_CU_QP_DELTA_ENABLED);
+ if (flags & V4L2_HEVC_PPS_FLAG_CU_QP_DELTA_ENABLED)
+ v4l2_hevc_enc_rbsp_ue(rbsp, pps->diff_cu_qp_delta_depth);
+
+ v4l2_hevc_enc_rbsp_se(rbsp, pps->pps_cb_qp_offset);
+ v4l2_hevc_enc_rbsp_se(rbsp, pps->pps_cr_qp_offset);
+ rbsp_flags(rbsp, flags,
+ V4L2_HEVC_PPS_FLAG_PPS_SLICE_CHROMA_QP_OFFSETS_PRESENT);
+ rbsp_flags(rbsp, flags, V4L2_HEVC_PPS_FLAG_WEIGHTED_PRED);
+ rbsp_flags(rbsp, flags, V4L2_HEVC_PPS_FLAG_WEIGHTED_BIPRED);
+ rbsp_flags(rbsp, flags, V4L2_HEVC_PPS_FLAG_TRANSQUANT_BYPASS_ENABLED);
+ rbsp_flags(rbsp, flags, V4L2_HEVC_PPS_FLAG_TILES_ENABLED);
+ rbsp_flags(rbsp, flags, V4L2_HEVC_PPS_FLAG_ENTROPY_CODING_SYNC_ENABLED);
+
+ if (flags & V4L2_HEVC_PPS_FLAG_TILES_ENABLED && !rbsp->error) {
+ bool uniform = flags & V4L2_HEVC_PPS_FLAG_UNIFORM_SPACING;
+
+ v4l2_hevc_enc_rbsp_ue(rbsp, pps->num_tile_columns_minus1);
+ v4l2_hevc_enc_rbsp_ue(rbsp, pps->num_tile_rows_minus1);
+ rbsp_flag(rbsp, uniform);
+ if (!uniform) {
+ for (i = 0; i < pps->num_tile_columns_minus1; i++)
+ v4l2_hevc_enc_rbsp_ue(rbsp,
+ pps->column_width_minus1[i]);
+ for (i = 0; i < pps->num_tile_rows_minus1; i++)
+ v4l2_hevc_enc_rbsp_ue(rbsp,
+ pps->row_height_minus1[i]);
+ }
+ rbsp_flags(rbsp, flags,
+ V4L2_HEVC_PPS_FLAG_LOOP_FILTER_ACROSS_TILES_ENABLED);
+ }
+
+ rbsp_flags(rbsp, flags,
+ V4L2_HEVC_PPS_FLAG_PPS_LOOP_FILTER_ACROSS_SLICES_ENABLED);
+
+ rbsp_flags(rbsp, flags,
+ V4L2_HEVC_PPS_FLAG_DEBLOCKING_FILTER_CONTROL_PRESENT);
+ if (flags & V4L2_HEVC_PPS_FLAG_DEBLOCKING_FILTER_CONTROL_PRESENT) {
+ rbsp_flags(rbsp, flags,
+ V4L2_HEVC_PPS_FLAG_DEBLOCKING_FILTER_OVERRIDE_ENABLED);
+ rbsp_flags(rbsp, flags,
+ V4L2_HEVC_PPS_FLAG_PPS_DISABLE_DEBLOCKING_FILTER);
+ if (!(flags & V4L2_HEVC_PPS_FLAG_PPS_DISABLE_DEBLOCKING_FILTER)) {
+ v4l2_hevc_enc_rbsp_se(rbsp, pps->pps_beta_offset_div2);
+ v4l2_hevc_enc_rbsp_se(rbsp, pps->pps_tc_offset_div2);
+ }
+ }
+
+ rbsp_flag(rbsp, 0); /* pps_scaling_list_data_present_flag */
+ rbsp_flags(rbsp, flags, V4L2_HEVC_PPS_FLAG_LISTS_MODIFICATION_PRESENT);
+ v4l2_hevc_enc_rbsp_ue(rbsp, pps->log2_parallel_merge_level_minus2);
+ rbsp_flags(rbsp, flags,
+ V4L2_HEVC_PPS_FLAG_SLICE_SEGMENT_HEADER_EXTENSION_PRESENT);
+ rbsp_flag(rbsp, 0); /* pps_extension_present_flag */
+
+ v4l2_hevc_enc_rbsp_nal_end(rbsp);
+
+ return rbsp->error;
+}
+EXPORT_SYMBOL_GPL(v4l2_hevc_enc_rbsp_pps);
+
+/* st_ref_pic_set(num_short_term_ref_pic_sets) (7.3.7), explicit form */
+static void rbsp_st_rps(struct v4l2_hevc_enc_rbsp *rbsp,
+ const struct v4l2_hevc_st_rps *rps,
+ unsigned int st_rps_idx)
+{
+ unsigned int i;
+
+ if (rps->num_negative_pics + rps->num_positive_pics >
+ V4L2_HEVC_MAX_ST_RPS_PICS) {
+ rbsp_fail(rbsp, -EINVAL);
+ return;
+ }
+
+ if (st_rps_idx)
+ rbsp_flag(rbsp, 0); /* inter_ref_pic_set_prediction_flag */
+
+ v4l2_hevc_enc_rbsp_ue(rbsp, rps->num_negative_pics);
+ v4l2_hevc_enc_rbsp_ue(rbsp, rps->num_positive_pics);
+
+ for (i = 0; i < rps->num_negative_pics; i++) {
+ v4l2_hevc_enc_rbsp_ue(rbsp, rps->delta_poc_s0_minus1[i]);
+ rbsp_flag(rbsp, rps->used_by_curr_pic_s0 & BIT(i));
+ }
+
+ for (i = 0; i < rps->num_positive_pics; i++) {
+ v4l2_hevc_enc_rbsp_ue(rbsp, rps->delta_poc_s1_minus1[i]);
+ rbsp_flag(rbsp, rps->used_by_curr_pic_s1 & BIT(i));
+ }
+}
+
+static unsigned int num_pic_total_curr(const struct v4l2_hevc_slice_header *sh)
+{
+ unsigned int count;
+ unsigned int i;
+
+ count = hweight32(sh->st_rps.used_by_curr_pic_s0 &
+ (BIT(sh->st_rps.num_negative_pics) - 1));
+ count += hweight32(sh->st_rps.used_by_curr_pic_s1 &
+ (BIT(sh->st_rps.num_positive_pics) - 1));
+
+ for (i = 0; i < sh->num_long_term_pics; i++)
+ count += sh->lt[i].used_by_curr_pic_lt;
+
+ return count;
+}
+
+/**
+ * v4l2_hevc_enc_rbsp_slice_header() - write a slice segment header (7.3.6)
+ * @rbsp: the writer
+ * @start_code: whether to write an Annex B start code
+ * @sps: the active SPS
+ * @pps: the active PPS
+ * @sh: the slice segment header syntax element values
+ *
+ * Writes the NAL unit header, then slice_segment_header() and
+ * byte_alignment(): the caller (usually the hardware) appends
+ * slice_segment_data() and the trailing bits. The short-term reference
+ * picture set is always coded in the slice header. Reference picture list
+ * modification is written as "no modification" and weighted prediction
+ * tables are not supported.
+ *
+ * Return: 0 or the first error of the writer.
+ */
+int v4l2_hevc_enc_rbsp_slice_header(struct v4l2_hevc_enc_rbsp *rbsp,
+ bool start_code,
+ const struct v4l2_ctrl_hevc_sps *sps,
+ const struct v4l2_ctrl_hevc_pps *pps,
+ const struct v4l2_hevc_slice_header *sh)
+{
+ unsigned int ctb_log2_size = sps->log2_min_luma_coding_block_size_minus3 +
+ 3 + sps->log2_diff_max_min_luma_coding_block_size;
+ unsigned int width_ctbs = DIV_ROUND_UP(sps->pic_width_in_luma_samples,
+ 1 << ctb_log2_size);
+ unsigned int height_ctbs = DIV_ROUND_UP(sps->pic_height_in_luma_samples,
+ 1 << ctb_log2_size);
+ unsigned int poc_lsb_bits = sps->log2_max_pic_order_cnt_lsb_minus4 + 4;
+ bool first = !sh->slice_segment_address;
+ bool dependent = sh->flags &
+ V4L2_HEVC_SLICE_HEADER_FLAG_DEPENDENT_SLICE_SEGMENT;
+ bool inter = sh->slice_type != V4L2_HEVC_SLICE_TYPE_I;
+ bool bipred = sh->slice_type == V4L2_HEVC_SLICE_TYPE_B;
+ bool temporal_mvp = false;
+ bool sao_luma = false;
+ bool sao_chroma = false;
+ bool deblocking_disabled;
+ u64 flags = sh->flags;
+ u64 pps_flags = pps->flags;
+ unsigned int i;
+
+ if (sh->slice_type > V4L2_HEVC_SLICE_TYPE_I ||
+ (first && dependent) ||
+ sh->num_long_term_pics > V4L2_HEVC_MAX_LT_PICS ||
+ (sh->num_long_term_pics &&
+ !(sps->flags & V4L2_HEVC_SPS_FLAG_LONG_TERM_REF_PICS_PRESENT)) ||
+ sps->flags & V4L2_HEVC_SPS_FLAG_SEPARATE_COLOUR_PLANE ||
+ (sh->slice_type == V4L2_HEVC_SLICE_TYPE_P &&
+ pps_flags & V4L2_HEVC_PPS_FLAG_WEIGHTED_PRED) ||
+ (bipred && pps_flags & V4L2_HEVC_PPS_FLAG_WEIGHTED_BIPRED) ||
+ sh->slice_segment_address >= width_ctbs * height_ctbs ||
+ (sh->num_entry_point_offsets && !sh->entry_point_offset_minus1))
+ rbsp_fail(rbsp, -EINVAL);
+
+ if (rbsp->error)
+ return rbsp->error;
+
+ v4l2_hevc_enc_rbsp_nal_begin(rbsp, start_code, sh->nal_unit_type,
+ sh->nuh_temporal_id_plus1);
+
+ rbsp_flag(rbsp, first);
+ if (v4l2_hevc_nal_is_irap(sh->nal_unit_type))
+ rbsp_flags(rbsp, flags,
+ V4L2_HEVC_ENCODE_FLAG_NO_OUTPUT_OF_PRIOR_PICS);
+ v4l2_hevc_enc_rbsp_ue(rbsp, pps->pic_parameter_set_id);
+
+ if (!first) {
+ if (pps_flags & V4L2_HEVC_PPS_FLAG_DEPENDENT_SLICE_SEGMENT_ENABLED)
+ rbsp_flag(rbsp, dependent);
+ v4l2_hevc_enc_rbsp_bits(rbsp, sh->slice_segment_address,
+ order_base_2(width_ctbs * height_ctbs));
+ }
+
+ deblocking_disabled =
+ pps_flags & V4L2_HEVC_PPS_FLAG_PPS_DISABLE_DEBLOCKING_FILTER;
+
+ if (dependent)
+ goto entry_points;
+
+ /* slice_reserved_flag[] */
+ v4l2_hevc_enc_rbsp_bits(rbsp, 0, pps->num_extra_slice_header_bits);
+ v4l2_hevc_enc_rbsp_ue(rbsp, sh->slice_type);
+
+ if (pps_flags & V4L2_HEVC_PPS_FLAG_OUTPUT_FLAG_PRESENT)
+ rbsp_flag(rbsp, !(flags & V4L2_HEVC_ENCODE_FLAG_NO_PIC_OUTPUT));
+
+ if (!v4l2_hevc_nal_is_idr(sh->nal_unit_type)) {
+ v4l2_hevc_enc_rbsp_bits(rbsp, sh->slice_pic_order_cnt_lsb,
+ poc_lsb_bits);
+
+ /* short_term_ref_pic_set_sps_flag */
+ rbsp_flag(rbsp, 0);
+ rbsp_st_rps(rbsp, &sh->st_rps, sps->num_short_term_ref_pic_sets);
+
+ if (sps->flags & V4L2_HEVC_SPS_FLAG_LONG_TERM_REF_PICS_PRESENT) {
+ v4l2_hevc_enc_rbsp_ue(rbsp, sh->num_long_term_pics);
+ for (i = 0; i < sh->num_long_term_pics; i++) {
+ const struct v4l2_hevc_lt_pic *lt = &sh->lt[i];
+
+ v4l2_hevc_enc_rbsp_bits(rbsp, lt->poc_lsb_lt,
+ poc_lsb_bits);
+ rbsp_flag(rbsp, lt->used_by_curr_pic_lt);
+ rbsp_flag(rbsp, lt->delta_poc_msb_present);
+ if (lt->delta_poc_msb_present)
+ v4l2_hevc_enc_rbsp_ue(rbsp,
+ lt->delta_poc_msb_cycle_lt);
+ }
+ }
+
+ if (sps->flags & V4L2_HEVC_SPS_FLAG_SPS_TEMPORAL_MVP_ENABLED) {
+ temporal_mvp = flags &
+ V4L2_HEVC_ENCODE_FLAG_SLICE_TEMPORAL_MVP_ENABLED;
+ rbsp_flag(rbsp, temporal_mvp);
+ }
+ }
+
+ if (sps->flags & V4L2_HEVC_SPS_FLAG_SAMPLE_ADAPTIVE_OFFSET) {
+ sao_luma = flags & V4L2_HEVC_ENCODE_FLAG_SLICE_SAO_LUMA;
+ rbsp_flag(rbsp, sao_luma);
+ if (sps->chroma_format_idc) {
+ sao_chroma = flags &
+ V4L2_HEVC_ENCODE_FLAG_SLICE_SAO_CHROMA;
+ rbsp_flag(rbsp, sao_chroma);
+ }
+ }
+
+ if (inter) {
+ bool override = flags &
+ V4L2_HEVC_ENCODE_FLAG_NUM_REF_IDX_ACTIVE_OVERRIDE;
+ unsigned int l0_active = pps->num_ref_idx_l0_default_active_minus1;
+ unsigned int l1_active = pps->num_ref_idx_l1_default_active_minus1;
+
+ rbsp_flag(rbsp, override);
+ if (override) {
+ l0_active = sh->num_ref_idx_l0_active_minus1;
+ v4l2_hevc_enc_rbsp_ue(rbsp, l0_active);
+ if (bipred) {
+ l1_active = sh->num_ref_idx_l1_active_minus1;
+ v4l2_hevc_enc_rbsp_ue(rbsp, l1_active);
+ }
+ }
+
+ if (pps_flags & V4L2_HEVC_PPS_FLAG_LISTS_MODIFICATION_PRESENT &&
+ num_pic_total_curr(sh) > 1) {
+ /* ref_pic_list_modification_flag_l0 and _l1 */
+ rbsp_flag(rbsp, 0);
+ if (bipred)
+ rbsp_flag(rbsp, 0);
+ }
+
+ if (bipred)
+ rbsp_flags(rbsp, flags, V4L2_HEVC_ENCODE_FLAG_MVD_L1_ZERO);
+
+ if (pps_flags & V4L2_HEVC_PPS_FLAG_CABAC_INIT_PRESENT)
+ rbsp_flags(rbsp, flags, V4L2_HEVC_ENCODE_FLAG_CABAC_INIT);
+
+ if (temporal_mvp) {
+ bool from_l0 = !bipred ||
+ flags & V4L2_HEVC_ENCODE_FLAG_COLLOCATED_FROM_L0;
+
+ if (bipred)
+ rbsp_flag(rbsp, from_l0);
+
+ if ((from_l0 && l0_active) || (!from_l0 && l1_active))
+ v4l2_hevc_enc_rbsp_ue(rbsp,
+ sh->collocated_ref_idx);
+ }
+
+ v4l2_hevc_enc_rbsp_ue(rbsp, sh->five_minus_max_num_merge_cand);
+ }
+
+ v4l2_hevc_enc_rbsp_se(rbsp, sh->slice_qp_delta);
+
+ if (pps_flags & V4L2_HEVC_PPS_FLAG_PPS_SLICE_CHROMA_QP_OFFSETS_PRESENT) {
+ v4l2_hevc_enc_rbsp_se(rbsp, sh->slice_cb_qp_offset);
+ v4l2_hevc_enc_rbsp_se(rbsp, sh->slice_cr_qp_offset);
+ }
+
+ if (pps_flags & V4L2_HEVC_PPS_FLAG_DEBLOCKING_FILTER_OVERRIDE_ENABLED) {
+ bool override = flags &
+ V4L2_HEVC_ENCODE_FLAG_DEBLOCKING_FILTER_OVERRIDE;
+
+ rbsp_flag(rbsp, override);
+ if (override) {
+ deblocking_disabled = flags &
+ V4L2_HEVC_ENCODE_FLAG_SLICE_DEBLOCKING_FILTER_DISABLED;
+ rbsp_flag(rbsp, deblocking_disabled);
+ if (!deblocking_disabled) {
+ v4l2_hevc_enc_rbsp_se(rbsp,
+ sh->slice_beta_offset_div2);
+ v4l2_hevc_enc_rbsp_se(rbsp,
+ sh->slice_tc_offset_div2);
+ }
+ }
+ }
+
+ if (pps_flags & V4L2_HEVC_PPS_FLAG_PPS_LOOP_FILTER_ACROSS_SLICES_ENABLED &&
+ (sao_luma || sao_chroma || !deblocking_disabled))
+ rbsp_flags(rbsp, flags,
+ V4L2_HEVC_ENCODE_FLAG_SLICE_LOOP_FILTER_ACROSS_SLICES_ENABLED);
+
+entry_points:
+ if (pps_flags & (V4L2_HEVC_PPS_FLAG_TILES_ENABLED |
+ V4L2_HEVC_PPS_FLAG_ENTROPY_CODING_SYNC_ENABLED)) {
+ v4l2_hevc_enc_rbsp_ue(rbsp, sh->num_entry_point_offsets);
+ if (sh->num_entry_point_offsets) {
+ unsigned int offset_len;
+ u32 offset_max = 0;
+
+ for (i = 0; i < sh->num_entry_point_offsets; i++)
+ offset_max = max(offset_max,
+ sh->entry_point_offset_minus1[i]);
+
+ offset_len = offset_max ? fls(offset_max) : 1;
+
+ /* offset_len_minus1 */
+ v4l2_hevc_enc_rbsp_ue(rbsp, offset_len - 1);
+ for (i = 0; i < sh->num_entry_point_offsets; i++)
+ v4l2_hevc_enc_rbsp_bits(rbsp,
+ sh->entry_point_offset_minus1[i],
+ offset_len);
+ }
+ }
+
+ /* slice_segment_header_extension_length */
+ if (pps_flags & V4L2_HEVC_PPS_FLAG_SLICE_SEGMENT_HEADER_EXTENSION_PRESENT)
+ v4l2_hevc_enc_rbsp_ue(rbsp, 0);
+
+ /* byte_alignment() */
+ v4l2_hevc_enc_rbsp_trailing_bits(rbsp);
+
+ return rbsp->error;
+}
+EXPORT_SYMBOL_GPL(v4l2_hevc_enc_rbsp_slice_header);
+
+MODULE_DESCRIPTION("V4L2 HEVC Encode RBSP");
+MODULE_LICENSE("GPL");
diff --git a/include/media/v4l2-hevc-enc-rbsp.h b/include/media/v4l2-hevc-enc-rbsp.h
new file mode 100644
index 000000000000..b593fd6c0d96
--- /dev/null
+++ b/include/media/v4l2-hevc-enc-rbsp.h
@@ -0,0 +1,279 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * V4L2 HEVC Encode RBSP
+ *
+ * Writes HEVC NAL units (VPS, SPS, PPS, access unit delimiter and slice
+ * segment headers) into a buffer, with Annex B start codes and emulation
+ * prevention.
+ */
+
+#ifndef _MEDIA_V4L2_HEVC_ENC_RBSP_H
+#define _MEDIA_V4L2_HEVC_ENC_RBSP_H
+
+#include <linux/bits.h>
+#include <linux/types.h>
+#include <linux/v4l2-controls.h>
+
+/**
+ * struct v4l2_hevc_enc_rbsp - HEVC NAL unit writer
+ *
+ * @data: start of the destination buffer
+ * @size: size of the destination buffer in bytes
+ * @offset: number of bytes written to @data
+ * @cache: bits not yet written to @data
+ * @cache_bits: number of valid bits in @cache, always less than 8 between
+ * calls
+ * @zero_bytes: number of consecutive zero bytes written last, used for
+ * emulation prevention
+ * @epb: whether emulation prevention is active (inside a NAL unit payload)
+ * @error: first error that happened, sticky until the next init. Writes
+ * after an error are ignored.
+ */
+struct v4l2_hevc_enc_rbsp {
+ u8 *data;
+ unsigned int size;
+ unsigned int offset;
+ u64 cache;
+ unsigned int cache_bits;
+ unsigned int zero_bytes;
+ bool epb;
+ int error;
+};
+
+#define V4L2_HEVC_PTL_FLAG_PROGRESSIVE_SOURCE 0x1
+#define V4L2_HEVC_PTL_FLAG_INTERLACED_SOURCE 0x2
+#define V4L2_HEVC_PTL_FLAG_NON_PACKED_CONSTRAINT 0x4
+#define V4L2_HEVC_PTL_FLAG_FRAME_ONLY_CONSTRAINT 0x8
+
+/**
+ * struct v4l2_hevc_ptl - HEVC general profile, tier and level (7.3.3)
+ *
+ * Sub-layer profile and level information is never written.
+ *
+ * @general_profile_space: general_profile_space
+ * @general_tier_flag: general_tier_flag
+ * @general_profile_idc: general_profile_idc
+ * @general_level_idc: general_level_idc (30 times the level number)
+ * @general_profile_compatibility_flags: general_profile_compatibility_flag[j]
+ * is bit (31 - j)
+ * @flags: see V4L2_HEVC_PTL_FLAG_{}
+ */
+struct v4l2_hevc_ptl {
+ u8 general_profile_space;
+ u8 general_tier_flag;
+ u8 general_profile_idc;
+ u8 general_level_idc;
+ u32 general_profile_compatibility_flags;
+ u32 flags;
+};
+
+#define V4L2_HEVC_SPS_VIDEO_FLAG_TEMPORAL_ID_NESTING BIT(0)
+#define V4L2_HEVC_SPS_VIDEO_FLAG_CONFORMANCE_WINDOW BIT(1)
+#define V4L2_HEVC_SPS_VIDEO_FLAG_VPS_TIMING_INFO_PRESENT BIT(2)
+#define V4L2_HEVC_SPS_VIDEO_FLAG_VUI_PARAMETERS_PRESENT BIT(3)
+#define V4L2_HEVC_SPS_VIDEO_FLAG_VUI_ASPECT_RATIO_INFO_PRESENT BIT(4)
+#define V4L2_HEVC_SPS_VIDEO_FLAG_VUI_OVERSCAN_INFO_PRESENT BIT(5)
+#define V4L2_HEVC_SPS_VIDEO_FLAG_VUI_OVERSCAN_APPROPRIATE BIT(6)
+#define V4L2_HEVC_SPS_VIDEO_FLAG_VUI_VIDEO_SIGNAL_TYPE_PRESENT BIT(7)
+#define V4L2_HEVC_SPS_VIDEO_FLAG_VUI_VIDEO_FULL_RANGE BIT(8)
+#define V4L2_HEVC_SPS_VIDEO_FLAG_VUI_COLOUR_DESCRIPTION_PRESENT BIT(9)
+#define V4L2_HEVC_SPS_VIDEO_FLAG_VUI_CHROMA_LOC_INFO_PRESENT BIT(10)
+#define V4L2_HEVC_SPS_VIDEO_FLAG_VUI_TIMING_INFO_PRESENT BIT(11)
+#define V4L2_HEVC_SPS_VIDEO_FLAG_VUI_POC_PROPORTIONAL_TO_TIMING BIT(12)
+#define V4L2_HEVC_SPS_VIDEO_FLAG_VUI_BITSTREAM_RESTRICTION BIT(13)
+#define V4L2_HEVC_SPS_VIDEO_FLAG_VUI_TILES_FIXED_STRUCTURE BIT(14)
+#define V4L2_HEVC_SPS_VIDEO_FLAG_VUI_MOTION_VECTORS_OVER_PIC_BOUNDARIES BIT(15)
+#define V4L2_HEVC_SPS_VIDEO_FLAG_VUI_RESTRICTED_REF_PIC_LISTS BIT(16)
+
+/**
+ * struct v4l2_hevc_sps_video - HEVC VPS/SPS fields not in v4l2_ctrl_hevc_sps
+ *
+ * The parts of the parameter sets that describe the video rather than the
+ * coding tools. The stateless encode core derives them from the format,
+ * the frame interval and the stateful codec controls.
+ *
+ * @ptl: general profile, tier and level
+ * @flags: see V4L2_HEVC_SPS_VIDEO_FLAG_{}
+ * @conf_win_left_offset: conformance window left offset, in chroma samples
+ * @conf_win_right_offset: conformance window right offset, in chroma samples
+ * @conf_win_top_offset: conformance window top offset, in chroma samples
+ * @conf_win_bottom_offset: conformance window bottom offset, in chroma
+ * samples
+ * @aspect_ratio_idc: aspect_ratio_idc (Table E.1)
+ * @sar_width: sar_width, with V4L2_HEVC_VUI_ASPECT_RATIO_IDC_EXTENDED
+ * @sar_height: sar_height, with V4L2_HEVC_VUI_ASPECT_RATIO_IDC_EXTENDED
+ * @video_format: video_format (Table E.2)
+ * @colour_primaries: colour_primaries (Table E.3)
+ * @transfer_characteristics: transfer_characteristics (Table E.4)
+ * @matrix_coeffs: matrix_coeffs (Table E.5)
+ * @chroma_sample_loc_type_top_field: chroma_sample_loc_type_top_field
+ * @chroma_sample_loc_type_bottom_field: chroma_sample_loc_type_bottom_field
+ * @num_units_in_tick: num_units_in_tick of the VUI and VPS timing info
+ * @time_scale: time_scale of the VUI and VPS timing info
+ * @num_ticks_poc_diff_one_minus1: num_ticks_poc_diff_one_minus1
+ * @min_spatial_segmentation_idc: min_spatial_segmentation_idc
+ * @max_bytes_per_pic_denom: max_bytes_per_pic_denom
+ * @max_bits_per_min_cu_denom: max_bits_per_min_cu_denom
+ * @log2_max_mv_length_horizontal: log2_max_mv_length_horizontal
+ * @log2_max_mv_length_vertical: log2_max_mv_length_vertical
+ */
+struct v4l2_hevc_sps_video {
+ struct v4l2_hevc_ptl ptl;
+ u32 flags;
+
+ u16 conf_win_left_offset;
+ u16 conf_win_right_offset;
+ u16 conf_win_top_offset;
+ u16 conf_win_bottom_offset;
+
+ u8 aspect_ratio_idc;
+ u16 sar_width;
+ u16 sar_height;
+
+ u8 video_format;
+ u8 colour_primaries;
+ u8 transfer_characteristics;
+ u8 matrix_coeffs;
+
+ u8 chroma_sample_loc_type_top_field;
+ u8 chroma_sample_loc_type_bottom_field;
+
+ u32 num_units_in_tick;
+ u32 time_scale;
+ u32 num_ticks_poc_diff_one_minus1;
+
+ u16 min_spatial_segmentation_idc;
+ u8 max_bytes_per_pic_denom;
+ u8 max_bits_per_min_cu_denom;
+ u8 log2_max_mv_length_horizontal;
+ u8 log2_max_mv_length_vertical;
+};
+
+/**
+ * struct v4l2_hevc_st_rps - HEVC short-term reference picture set (7.3.7)
+ *
+ * Always written explicitly (inter_ref_pic_set_prediction_flag = 0).
+ *
+ * @num_negative_pics: num_negative_pics
+ * @num_positive_pics: num_positive_pics
+ * @used_by_curr_pic_s0: bit i is used_by_curr_pic_s0_flag[i]
+ * @used_by_curr_pic_s1: bit i is used_by_curr_pic_s1_flag[i]
+ * @delta_poc_s0_minus1: delta_poc_s0_minus1[]
+ * @delta_poc_s1_minus1: delta_poc_s1_minus1[]
+ */
+struct v4l2_hevc_st_rps {
+ u8 num_negative_pics;
+ u8 num_positive_pics;
+ u16 used_by_curr_pic_s0;
+ u16 used_by_curr_pic_s1;
+ u16 delta_poc_s0_minus1[16];
+ u16 delta_poc_s1_minus1[16];
+};
+
+/**
+ * struct v4l2_hevc_lt_pic - HEVC long-term picture of a slice header
+ *
+ * @poc_lsb_lt: poc_lsb_lt[i]
+ * @used_by_curr_pic_lt: used_by_curr_pic_lt_flag[i]
+ * @delta_poc_msb_present: delta_poc_msb_present_flag[i]
+ * @delta_poc_msb_cycle_lt: delta_poc_msb_cycle_lt[i]
+ */
+struct v4l2_hevc_lt_pic {
+ u16 poc_lsb_lt;
+ bool used_by_curr_pic_lt;
+ bool delta_poc_msb_present;
+ u32 delta_poc_msb_cycle_lt;
+};
+
+/* Slice header flags beyond the V4L2_HEVC_ENCODE_FLAG_{} uAPI flags. */
+#define V4L2_HEVC_SLICE_HEADER_FLAG_DEPENDENT_SLICE_SEGMENT BIT_ULL(32)
+
+/**
+ * struct v4l2_hevc_slice_header - HEVC slice segment header (7.3.6)
+ *
+ * The values of the syntax elements, resolved. Elements that the active
+ * SPS/PPS make absent are ignored.
+ *
+ * @nal_unit_type: nal_unit_type
+ * @nuh_temporal_id_plus1: nuh_temporal_id_plus1
+ * @slice_type: slice_type
+ * @slice_segment_address: slice_segment_address, 0 for the first slice
+ * segment of the picture
+ * @slice_pic_order_cnt_lsb: slice_pic_order_cnt_lsb
+ * @st_rps: short-term reference picture set, coded in the slice header
+ * @num_long_term_pics: num_long_term_pics
+ * @lt: long-term pictures
+ * @num_ref_idx_l0_active_minus1: num_ref_idx_l0_active_minus1
+ * @num_ref_idx_l1_active_minus1: num_ref_idx_l1_active_minus1
+ * @collocated_ref_idx: collocated_ref_idx
+ * @five_minus_max_num_merge_cand: five_minus_max_num_merge_cand
+ * @slice_qp_delta: slice_qp_delta
+ * @slice_cb_qp_offset: slice_cb_qp_offset
+ * @slice_cr_qp_offset: slice_cr_qp_offset
+ * @slice_beta_offset_div2: slice_beta_offset_div2
+ * @slice_tc_offset_div2: slice_tc_offset_div2
+ * @num_entry_point_offsets: num_entry_point_offsets
+ * @entry_point_offset_minus1: entry_point_offset_minus1[], must point to
+ * @num_entry_point_offsets values when non-zero
+ * @flags: V4L2_HEVC_ENCODE_FLAG_{} and V4L2_HEVC_SLICE_HEADER_FLAG_{}
+ */
+struct v4l2_hevc_slice_header {
+ u8 nal_unit_type;
+ u8 nuh_temporal_id_plus1;
+ u8 slice_type;
+ u32 slice_segment_address;
+ u16 slice_pic_order_cnt_lsb;
+
+ struct v4l2_hevc_st_rps st_rps;
+ u8 num_long_term_pics;
+ struct v4l2_hevc_lt_pic lt[16];
+
+ u8 num_ref_idx_l0_active_minus1;
+ u8 num_ref_idx_l1_active_minus1;
+ u8 collocated_ref_idx;
+ u8 five_minus_max_num_merge_cand;
+ s8 slice_qp_delta;
+ s8 slice_cb_qp_offset;
+ s8 slice_cr_qp_offset;
+ s8 slice_beta_offset_div2;
+ s8 slice_tc_offset_div2;
+
+ u32 num_entry_point_offsets;
+ const u32 *entry_point_offset_minus1;
+
+ u64 flags;
+};
+
+void v4l2_hevc_enc_rbsp_init(struct v4l2_hevc_enc_rbsp *rbsp, u8 *data,
+ unsigned int size);
+unsigned int v4l2_hevc_enc_rbsp_bytes(const struct v4l2_hevc_enc_rbsp *rbsp);
+int v4l2_hevc_enc_rbsp_error(const struct v4l2_hevc_enc_rbsp *rbsp);
+
+void v4l2_hevc_enc_rbsp_bits(struct v4l2_hevc_enc_rbsp *rbsp, u32 value,
+ unsigned int count);
+void v4l2_hevc_enc_rbsp_ue(struct v4l2_hevc_enc_rbsp *rbsp, u32 value);
+void v4l2_hevc_enc_rbsp_se(struct v4l2_hevc_enc_rbsp *rbsp, s32 value);
+void v4l2_hevc_enc_rbsp_trailing_bits(struct v4l2_hevc_enc_rbsp *rbsp);
+void v4l2_hevc_enc_rbsp_nal_begin(struct v4l2_hevc_enc_rbsp *rbsp,
+ bool start_code, u8 nal_unit_type,
+ u8 nuh_temporal_id_plus1);
+void v4l2_hevc_enc_rbsp_nal_end(struct v4l2_hevc_enc_rbsp *rbsp);
+
+int v4l2_hevc_enc_rbsp_aud(struct v4l2_hevc_enc_rbsp *rbsp, bool start_code,
+ u8 pic_type, u8 nuh_temporal_id_plus1);
+int v4l2_hevc_enc_rbsp_vps(struct v4l2_hevc_enc_rbsp *rbsp, bool start_code,
+ const struct v4l2_ctrl_hevc_sps *sps,
+ const struct v4l2_hevc_sps_video *sps_video);
+int v4l2_hevc_enc_rbsp_sps(struct v4l2_hevc_enc_rbsp *rbsp, bool start_code,
+ const struct v4l2_ctrl_hevc_sps *sps,
+ const struct v4l2_hevc_sps_video *sps_video);
+int v4l2_hevc_enc_rbsp_pps(struct v4l2_hevc_enc_rbsp *rbsp, bool start_code,
+ const struct v4l2_ctrl_hevc_sps *sps,
+ const struct v4l2_ctrl_hevc_pps *pps);
+int v4l2_hevc_enc_rbsp_slice_header(struct v4l2_hevc_enc_rbsp *rbsp,
+ bool start_code,
+ const struct v4l2_ctrl_hevc_sps *sps,
+ const struct v4l2_ctrl_hevc_pps *pps,
+ const struct v4l2_hevc_slice_header *sh);
+
+#endif
--
2.55.0
next prev parent reply other threads:[~2026-11-10 10:07 UTC|newest]
Thread overview: 11+ 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 via B4 Relay
2026-11-10 10:07 ` [PATCH RFC 01/10] media: hevc: Add H.265 syntax definitions Arun Iyengar via B4 Relay
2026-11-10 10:07 ` [PATCH RFC 02/10] media: uapi: Add HEVC stateless encode support Arun Iyengar via B4 Relay
2026-11-10 10:07 ` Arun Iyengar via B4 Relay [this message]
2026-11-10 10:07 ` [PATCH RFC 04/10] media: hevc: Add KUnit tests for the stateless encode RBSP writer Arun Iyengar via B4 Relay
2026-11-10 10:07 ` [PATCH RFC 05/10] media: hevc: Add stateless encode core Arun Iyengar via B4 Relay
2026-11-10 10:07 ` [PATCH RFC 06/10] media: hevc: Add KUnit tests for the " 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 via B4 Relay
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 via B4 Relay
2026-11-10 10:07 ` [PATCH RFC 10/10] media: docs: Document the HEVC stateless encode uAPI 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-3-38ae9fcfedd4@gmail.com \
--to=devnull+aiyengar1990.gmail.com@kernel.org \
--cc=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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®