Resguardo inicial

This commit is contained in:
lastdragon
2026-09-06 12:53:21 -06:00
parent 662efe3c2a
commit ad2088d178
94853 changed files with 43200404 additions and 0 deletions
@@ -0,0 +1,19 @@
# SPDX-License-Identifier: GPL-2.0-only
comment "Allegro DVT media platform drivers"
config VIDEO_ALLEGRO_DVT
tristate "Allegro DVT Video IP Core"
depends on V4L_MEM2MEM_DRIVERS
depends on VIDEO_DEV
depends on ARCH_ZYNQMP || COMPILE_TEST
select V4L2_MEM2MEM_DEV
select VIDEOBUF2_DMA_CONTIG
select REGMAP_MMIO
help
Support for the encoder video IP core by Allegro DVT. This core is
found for example on the Xilinx ZynqMP SoC in the EV family and is
called VCU in the reference manual.
To compile this driver as a module, choose M here: the module
will be called allegro.
@@ -0,0 +1,6 @@
# SPDX-License-Identifier: GPL-2.0
allegro-objs := allegro-core.o allegro-mail.o
allegro-objs += nal-rbsp.o nal-h264.o nal-hevc.o
obj-$(CONFIG_VIDEO_ALLEGRO_DVT) += allegro.o
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,549 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2019 Pengutronix, Michael Tretter <kernel@pengutronix.de>
*
* Helper functions for handling messages that are send via mailbox to the
* Allegro VCU firmware.
*/
#include <linux/bitfield.h>
#include <linux/export.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/videodev2.h>
#include "allegro-mail.h"
const char *msg_type_name(enum mcu_msg_type type)
{
static char buf[13];
switch (type) {
case MCU_MSG_TYPE_INIT:
return "INIT";
case MCU_MSG_TYPE_CREATE_CHANNEL:
return "CREATE_CHANNEL";
case MCU_MSG_TYPE_DESTROY_CHANNEL:
return "DESTROY_CHANNEL";
case MCU_MSG_TYPE_ENCODE_FRAME:
return "ENCODE_FRAME";
case MCU_MSG_TYPE_PUT_STREAM_BUFFER:
return "PUT_STREAM_BUFFER";
case MCU_MSG_TYPE_PUSH_BUFFER_INTERMEDIATE:
return "PUSH_BUFFER_INTERMEDIATE";
case MCU_MSG_TYPE_PUSH_BUFFER_REFERENCE:
return "PUSH_BUFFER_REFERENCE";
default:
snprintf(buf, sizeof(buf), "(0x%04x)", type);
return buf;
}
}
EXPORT_SYMBOL(msg_type_name);
static ssize_t
allegro_enc_init(u32 *dst, struct mcu_msg_init_request *msg)
{
unsigned int i = 0;
enum mcu_msg_version version = msg->header.version;
dst[i++] = msg->reserved0;
dst[i++] = msg->suballoc_dma;
dst[i++] = msg->suballoc_size;
dst[i++] = msg->encoder_buffer_size;
dst[i++] = msg->encoder_buffer_color_depth;
dst[i++] = msg->num_cores;
if (version >= MCU_MSG_VERSION_2019_2) {
dst[i++] = msg->clk_rate;
dst[i++] = 0;
}
return i * sizeof(*dst);
}
static inline u32 settings_get_mcu_codec(struct create_channel_param *param)
{
enum mcu_msg_version version = param->version;
u32 pixelformat = param->codec;
if (version < MCU_MSG_VERSION_2019_2) {
switch (pixelformat) {
case V4L2_PIX_FMT_HEVC:
return 2;
case V4L2_PIX_FMT_H264:
default:
return 1;
}
} else {
switch (pixelformat) {
case V4L2_PIX_FMT_HEVC:
return 1;
case V4L2_PIX_FMT_H264:
default:
return 0;
}
}
}
ssize_t
allegro_encode_config_blob(u32 *dst, struct create_channel_param *param)
{
enum mcu_msg_version version = param->version;
unsigned int i = 0;
unsigned int j = 0;
u32 val;
unsigned int codec = settings_get_mcu_codec(param);
if (version >= MCU_MSG_VERSION_2019_2)
dst[i++] = param->layer_id;
dst[i++] = FIELD_PREP(GENMASK(31, 16), param->height) |
FIELD_PREP(GENMASK(15, 0), param->width);
if (version >= MCU_MSG_VERSION_2019_2)
dst[i++] = param->videomode;
dst[i++] = param->format;
if (version < MCU_MSG_VERSION_2019_2)
dst[i++] = param->colorspace;
dst[i++] = param->src_mode;
if (version >= MCU_MSG_VERSION_2019_2)
dst[i++] = param->src_bit_depth;
dst[i++] = FIELD_PREP(GENMASK(31, 24), codec) |
FIELD_PREP(GENMASK(23, 8), param->constraint_set_flags) |
FIELD_PREP(GENMASK(7, 0), param->profile);
dst[i++] = FIELD_PREP(GENMASK(31, 16), param->tier) |
FIELD_PREP(GENMASK(15, 0), param->level);
val = 0;
val |= param->temporal_mvp_enable ? BIT(20) : 0;
val |= FIELD_PREP(GENMASK(7, 4), param->log2_max_frame_num);
if (version >= MCU_MSG_VERSION_2019_2)
val |= FIELD_PREP(GENMASK(3, 0), param->log2_max_poc - 1);
else
val |= FIELD_PREP(GENMASK(3, 0), param->log2_max_poc);
dst[i++] = val;
val = 0;
val |= param->enable_reordering ? BIT(0) : 0;
val |= param->dbf_ovr_en ? BIT(2) : 0;
val |= param->override_lf ? BIT(12) : 0;
dst[i++] = val;
if (version >= MCU_MSG_VERSION_2019_2) {
val = 0;
val |= param->custom_lda ? BIT(2) : 0;
val |= param->rdo_cost_mode ? BIT(20) : 0;
dst[i++] = val;
val = 0;
val |= param->lf ? BIT(2) : 0;
val |= param->lf_x_tile ? BIT(3) : 0;
val |= param->lf_x_slice ? BIT(4) : 0;
dst[i++] = val;
} else {
val = 0;
dst[i++] = val;
}
dst[i++] = FIELD_PREP(GENMASK(15, 8), param->beta_offset) |
FIELD_PREP(GENMASK(7, 0), param->tc_offset);
dst[i++] = param->unknown11;
dst[i++] = param->unknown12;
dst[i++] = param->num_slices;
dst[i++] = param->encoder_buffer_offset;
dst[i++] = param->encoder_buffer_enabled;
dst[i++] = FIELD_PREP(GENMASK(31, 16), param->clip_vrt_range) |
FIELD_PREP(GENMASK(15, 0), param->clip_hrz_range);
dst[i++] = FIELD_PREP(GENMASK(31, 16), param->me_range[1]) |
FIELD_PREP(GENMASK(15, 0), param->me_range[0]);
dst[i++] = FIELD_PREP(GENMASK(31, 16), param->me_range[3]) |
FIELD_PREP(GENMASK(15, 0), param->me_range[2]);
dst[i++] = FIELD_PREP(GENMASK(31, 24), param->min_tu_size) |
FIELD_PREP(GENMASK(23, 16), param->max_tu_size) |
FIELD_PREP(GENMASK(15, 8), param->min_cu_size) |
FIELD_PREP(GENMASK(8, 0), param->max_cu_size);
dst[i++] = FIELD_PREP(GENMASK(15, 8), param->max_transfo_depth_intra) |
FIELD_PREP(GENMASK(7, 0), param->max_transfo_depth_inter);
dst[i++] = param->entropy_mode;
dst[i++] = param->wp_mode;
dst[i++] = param->rate_control_mode;
dst[i++] = param->initial_rem_delay;
dst[i++] = param->cpb_size;
dst[i++] = FIELD_PREP(GENMASK(31, 16), param->clk_ratio) |
FIELD_PREP(GENMASK(15, 0), param->framerate);
dst[i++] = param->target_bitrate;
dst[i++] = param->max_bitrate;
dst[i++] = FIELD_PREP(GENMASK(31, 16), param->min_qp) |
FIELD_PREP(GENMASK(15, 0), param->initial_qp);
dst[i++] = FIELD_PREP(GENMASK(31, 16), param->ip_delta) |
FIELD_PREP(GENMASK(15, 0), param->max_qp);
dst[i++] = FIELD_PREP(GENMASK(31, 16), param->golden_ref) |
FIELD_PREP(GENMASK(15, 0), param->pb_delta);
dst[i++] = FIELD_PREP(GENMASK(31, 16), param->golden_ref_frequency) |
FIELD_PREP(GENMASK(15, 0), param->golden_delta);
if (version >= MCU_MSG_VERSION_2019_2)
dst[i++] = param->rate_control_option;
else
dst[i++] = 0;
if (version >= MCU_MSG_VERSION_2019_2) {
dst[i++] = param->num_pixel;
dst[i++] = FIELD_PREP(GENMASK(31, 16), param->max_pixel_value) |
FIELD_PREP(GENMASK(15, 0), param->max_psnr);
for (j = 0; j < 3; j++)
dst[i++] = param->maxpicturesize[j];
}
if (version >= MCU_MSG_VERSION_2019_2)
dst[i++] = param->gop_ctrl_mode;
else
dst[i++] = 0;
if (version >= MCU_MSG_VERSION_2019_2)
dst[i++] = FIELD_PREP(GENMASK(31, 24), param->freq_golden_ref) |
FIELD_PREP(GENMASK(23, 16), param->num_b) |
FIELD_PREP(GENMASK(15, 0), param->gop_length);
dst[i++] = param->freq_idr;
if (version >= MCU_MSG_VERSION_2019_2)
dst[i++] = param->enable_lt;
dst[i++] = param->freq_lt;
dst[i++] = param->gdr_mode;
if (version < MCU_MSG_VERSION_2019_2)
dst[i++] = FIELD_PREP(GENMASK(31, 24), param->freq_golden_ref) |
FIELD_PREP(GENMASK(23, 16), param->num_b) |
FIELD_PREP(GENMASK(15, 0), param->gop_length);
if (version >= MCU_MSG_VERSION_2019_2)
dst[i++] = param->tmpdqp;
dst[i++] = param->subframe_latency;
dst[i++] = param->lda_control_mode;
if (version < MCU_MSG_VERSION_2019_2)
dst[i++] = param->unknown41;
if (version >= MCU_MSG_VERSION_2019_2) {
for (j = 0; j < 6; j++)
dst[i++] = param->lda_factors[j];
dst[i++] = param->max_num_merge_cand;
}
return i * sizeof(*dst);
}
static ssize_t
allegro_enc_create_channel(u32 *dst, struct mcu_msg_create_channel *msg)
{
enum mcu_msg_version version = msg->header.version;
unsigned int i = 0;
dst[i++] = msg->user_id;
if (version >= MCU_MSG_VERSION_2019_2) {
dst[i++] = msg->blob_mcu_addr;
} else {
memcpy(&dst[i], msg->blob, msg->blob_size);
i += msg->blob_size / sizeof(*dst);
}
if (version >= MCU_MSG_VERSION_2019_2)
dst[i++] = msg->ep1_addr;
return i * sizeof(*dst);
}
ssize_t allegro_decode_config_blob(struct create_channel_param *param,
struct mcu_msg_create_channel_response *msg,
u32 *src)
{
enum mcu_msg_version version = msg->header.version;
if (version >= MCU_MSG_VERSION_2019_2) {
param->num_ref_idx_l0 = FIELD_GET(GENMASK(7, 4), src[9]);
param->num_ref_idx_l1 = FIELD_GET(GENMASK(11, 8), src[9]);
} else {
param->num_ref_idx_l0 = msg->num_ref_idx_l0;
param->num_ref_idx_l1 = msg->num_ref_idx_l1;
}
return 0;
}
static ssize_t
allegro_enc_destroy_channel(u32 *dst, struct mcu_msg_destroy_channel *msg)
{
unsigned int i = 0;
dst[i++] = msg->channel_id;
return i * sizeof(*dst);
}
static ssize_t
allegro_enc_push_buffers(u32 *dst, struct mcu_msg_push_buffers_internal *msg)
{
unsigned int i = 0;
struct mcu_msg_push_buffers_internal_buffer *buffer;
unsigned int num_buffers = msg->num_buffers;
unsigned int j;
dst[i++] = msg->channel_id;
for (j = 0; j < num_buffers; j++) {
buffer = &msg->buffer[j];
dst[i++] = buffer->dma_addr;
dst[i++] = buffer->mcu_addr;
dst[i++] = buffer->size;
}
return i * sizeof(*dst);
}
static ssize_t
allegro_enc_put_stream_buffer(u32 *dst,
struct mcu_msg_put_stream_buffer *msg)
{
unsigned int i = 0;
dst[i++] = msg->channel_id;
dst[i++] = msg->dma_addr;
dst[i++] = msg->mcu_addr;
dst[i++] = msg->size;
dst[i++] = msg->offset;
dst[i++] = lower_32_bits(msg->dst_handle);
dst[i++] = upper_32_bits(msg->dst_handle);
return i * sizeof(*dst);
}
static ssize_t
allegro_enc_encode_frame(u32 *dst, struct mcu_msg_encode_frame *msg)
{
enum mcu_msg_version version = msg->header.version;
unsigned int i = 0;
dst[i++] = msg->channel_id;
dst[i++] = msg->reserved;
dst[i++] = msg->encoding_options;
dst[i++] = FIELD_PREP(GENMASK(31, 16), msg->padding) |
FIELD_PREP(GENMASK(15, 0), msg->pps_qp);
if (version >= MCU_MSG_VERSION_2019_2) {
dst[i++] = 0;
dst[i++] = 0;
dst[i++] = 0;
dst[i++] = 0;
}
dst[i++] = lower_32_bits(msg->user_param);
dst[i++] = upper_32_bits(msg->user_param);
dst[i++] = lower_32_bits(msg->src_handle);
dst[i++] = upper_32_bits(msg->src_handle);
dst[i++] = msg->request_options;
dst[i++] = msg->src_y;
dst[i++] = msg->src_uv;
if (version >= MCU_MSG_VERSION_2019_2)
dst[i++] = msg->is_10_bit;
dst[i++] = msg->stride;
if (version >= MCU_MSG_VERSION_2019_2)
dst[i++] = msg->format;
dst[i++] = msg->ep2;
dst[i++] = lower_32_bits(msg->ep2_v);
dst[i++] = upper_32_bits(msg->ep2_v);
return i * sizeof(*dst);
}
static ssize_t
allegro_dec_init(struct mcu_msg_init_response *msg, u32 *src)
{
unsigned int i = 0;
msg->reserved0 = src[i++];
return i * sizeof(*src);
}
static ssize_t
allegro_dec_create_channel(struct mcu_msg_create_channel_response *msg,
u32 *src)
{
enum mcu_msg_version version = msg->header.version;
unsigned int i = 0;
msg->channel_id = src[i++];
msg->user_id = src[i++];
/*
* Version >= MCU_MSG_VERSION_2019_2 is handled in
* allegro_decode_config_blob().
*/
if (version < MCU_MSG_VERSION_2019_2) {
msg->options = src[i++];
msg->num_core = src[i++];
msg->num_ref_idx_l0 = FIELD_GET(GENMASK(7, 4), src[i]);
msg->num_ref_idx_l1 = FIELD_GET(GENMASK(11, 8), src[i++]);
}
msg->int_buffers_count = src[i++];
msg->int_buffers_size = src[i++];
msg->rec_buffers_count = src[i++];
msg->rec_buffers_size = src[i++];
msg->reserved = src[i++];
msg->error_code = src[i++];
return i * sizeof(*src);
}
static ssize_t
allegro_dec_destroy_channel(struct mcu_msg_destroy_channel_response *msg,
u32 *src)
{
unsigned int i = 0;
msg->channel_id = src[i++];
return i * sizeof(*src);
}
static ssize_t
allegro_dec_encode_frame(struct mcu_msg_encode_frame_response *msg, u32 *src)
{
enum mcu_msg_version version = msg->header.version;
unsigned int i = 0;
unsigned int j;
msg->channel_id = src[i++];
msg->dst_handle = src[i++];
msg->dst_handle |= (((u64)src[i++]) << 32);
msg->user_param = src[i++];
msg->user_param |= (((u64)src[i++]) << 32);
msg->src_handle = src[i++];
msg->src_handle |= (((u64)src[i++]) << 32);
msg->skip = FIELD_GET(GENMASK(31, 16), src[i]);
msg->is_ref = FIELD_GET(GENMASK(15, 0), src[i++]);
msg->initial_removal_delay = src[i++];
msg->dpb_output_delay = src[i++];
msg->size = src[i++];
msg->frame_tag_size = src[i++];
msg->stuffing = src[i++];
msg->filler = src[i++];
msg->num_row = FIELD_GET(GENMASK(31, 16), src[i]);
msg->num_column = FIELD_GET(GENMASK(15, 0), src[i++]);
msg->num_ref_idx_l1 = FIELD_GET(GENMASK(31, 24), src[i]);
msg->num_ref_idx_l0 = FIELD_GET(GENMASK(23, 16), src[i]);
msg->qp = FIELD_GET(GENMASK(15, 0), src[i++]);
msg->partition_table_offset = src[i++];
msg->partition_table_size = src[i++];
msg->sum_complex = src[i++];
for (j = 0; j < 4; j++)
msg->tile_width[j] = src[i++];
for (j = 0; j < 22; j++)
msg->tile_height[j] = src[i++];
msg->error_code = src[i++];
msg->slice_type = src[i++];
msg->pic_struct = src[i++];
msg->reserved = FIELD_GET(GENMASK(31, 24), src[i]);
msg->is_last_slice = FIELD_GET(GENMASK(23, 16), src[i]);
msg->is_first_slice = FIELD_GET(GENMASK(15, 8), src[i]);
msg->is_idr = FIELD_GET(GENMASK(7, 0), src[i++]);
msg->reserved1 = FIELD_GET(GENMASK(31, 16), src[i]);
msg->pps_qp = FIELD_GET(GENMASK(15, 0), src[i++]);
msg->reserved2 = src[i++];
if (version >= MCU_MSG_VERSION_2019_2) {
msg->reserved3 = src[i++];
msg->reserved4 = src[i++];
msg->reserved5 = src[i++];
msg->reserved6 = src[i++];
}
return i * sizeof(*src);
}
/**
* allegro_encode_mail() - Encode allegro messages to firmware format
* @dst: Pointer to the memory that will be filled with data
* @msg: The allegro message that will be encoded
*/
ssize_t allegro_encode_mail(u32 *dst, void *msg)
{
const struct mcu_msg_header *header = msg;
ssize_t size;
if (!msg || !dst)
return -EINVAL;
switch (header->type) {
case MCU_MSG_TYPE_INIT:
size = allegro_enc_init(&dst[1], msg);
break;
case MCU_MSG_TYPE_CREATE_CHANNEL:
size = allegro_enc_create_channel(&dst[1], msg);
break;
case MCU_MSG_TYPE_DESTROY_CHANNEL:
size = allegro_enc_destroy_channel(&dst[1], msg);
break;
case MCU_MSG_TYPE_ENCODE_FRAME:
size = allegro_enc_encode_frame(&dst[1], msg);
break;
case MCU_MSG_TYPE_PUT_STREAM_BUFFER:
size = allegro_enc_put_stream_buffer(&dst[1], msg);
break;
case MCU_MSG_TYPE_PUSH_BUFFER_INTERMEDIATE:
case MCU_MSG_TYPE_PUSH_BUFFER_REFERENCE:
size = allegro_enc_push_buffers(&dst[1], msg);
break;
default:
return -EINVAL;
}
/*
* The encoded messages might have different length depending on
* the firmware version or certain fields. Therefore, we have to
* set the body length after encoding the message.
*/
dst[0] = FIELD_PREP(GENMASK(31, 16), header->type) |
FIELD_PREP(GENMASK(15, 0), size);
return size + sizeof(*dst);
}
/**
* allegro_decode_mail() - Parse allegro messages from the firmware.
* @msg: The mcu_msg_response that will be filled with parsed values.
* @src: Pointer to the memory that will be parsed
*
* The message format in the mailbox depends on the firmware. Parse the
* different formats into a uniform message format that can be used without
* taking care of the firmware version.
*/
int allegro_decode_mail(void *msg, u32 *src)
{
struct mcu_msg_header *header;
if (!src || !msg)
return -EINVAL;
header = msg;
header->type = FIELD_GET(GENMASK(31, 16), src[0]);
src++;
switch (header->type) {
case MCU_MSG_TYPE_INIT:
allegro_dec_init(msg, src);
break;
case MCU_MSG_TYPE_CREATE_CHANNEL:
allegro_dec_create_channel(msg, src);
break;
case MCU_MSG_TYPE_DESTROY_CHANNEL:
allegro_dec_destroy_channel(msg, src);
break;
case MCU_MSG_TYPE_ENCODE_FRAME:
allegro_dec_encode_frame(msg, src);
break;
default:
return -EINVAL;
}
return 0;
}
@@ -0,0 +1,297 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) 2019 Pengutronix, Michael Tretter <kernel@pengutronix.de>
*
* Allegro VCU firmware mailbox mail definitions
*/
#ifndef ALLEGRO_MAIL_H
#define ALLEGRO_MAIL_H
#include <linux/kernel.h>
enum mcu_msg_type {
MCU_MSG_TYPE_INIT = 0x0000,
MCU_MSG_TYPE_CREATE_CHANNEL = 0x0005,
MCU_MSG_TYPE_DESTROY_CHANNEL = 0x0006,
MCU_MSG_TYPE_ENCODE_FRAME = 0x0007,
MCU_MSG_TYPE_PUT_STREAM_BUFFER = 0x0012,
MCU_MSG_TYPE_PUSH_BUFFER_INTERMEDIATE = 0x000e,
MCU_MSG_TYPE_PUSH_BUFFER_REFERENCE = 0x000f,
};
enum mcu_msg_version {
MCU_MSG_VERSION_2018_2,
MCU_MSG_VERSION_2019_2,
};
const char *msg_type_name(enum mcu_msg_type type);
struct mcu_msg_header {
enum mcu_msg_type type;
enum mcu_msg_version version;
};
struct mcu_msg_init_request {
struct mcu_msg_header header;
u32 reserved0; /* maybe a unused channel id */
u32 suballoc_dma;
u32 suballoc_size;
s32 encoder_buffer_size;
s32 encoder_buffer_color_depth;
s32 num_cores;
s32 clk_rate;
};
struct mcu_msg_init_response {
struct mcu_msg_header header;
u32 reserved0;
};
struct create_channel_param {
enum mcu_msg_version version;
u32 layer_id;
u16 width;
u16 height;
u32 videomode;
u32 format;
u32 colorspace;
u32 src_mode;
u32 src_bit_depth;
u8 profile;
u16 constraint_set_flags;
u32 codec;
u16 level;
u16 tier;
u32 log2_max_poc;
u32 log2_max_frame_num;
u32 temporal_mvp_enable;
u32 enable_reordering;
u32 dbf_ovr_en;
u32 override_lf;
u32 num_ref_idx_l0;
u32 num_ref_idx_l1;
u32 custom_lda;
u32 rdo_cost_mode;
u32 lf;
u32 lf_x_tile;
u32 lf_x_slice;
s8 beta_offset;
s8 tc_offset;
u16 reserved10;
u32 unknown11;
u32 unknown12;
u16 num_slices;
u32 encoder_buffer_offset;
u32 encoder_buffer_enabled;
u16 clip_hrz_range;
u16 clip_vrt_range;
u16 me_range[4];
u8 max_cu_size;
u8 min_cu_size;
u8 max_tu_size;
u8 min_tu_size;
u8 max_transfo_depth_inter;
u8 max_transfo_depth_intra;
u16 reserved20;
u32 entropy_mode;
u32 wp_mode;
/* rate control param */
u32 rate_control_mode;
u32 initial_rem_delay;
u32 cpb_size;
u16 framerate;
u16 clk_ratio;
u32 target_bitrate;
u32 max_bitrate;
u16 initial_qp;
u16 min_qp;
u16 max_qp;
s16 ip_delta;
s16 pb_delta;
u16 golden_ref;
u16 golden_delta;
u16 golden_ref_frequency;
u32 rate_control_option;
u32 num_pixel;
u16 max_psnr;
u16 max_pixel_value;
u32 maxpicturesize[3];
/* gop param */
u32 gop_ctrl_mode;
u32 freq_idr;
u32 freq_lt;
u32 gdr_mode;
u16 gop_length;
u8 num_b;
u8 freq_golden_ref;
u32 enable_lt;
u32 tmpdqp;
u32 subframe_latency;
u32 lda_control_mode;
u32 unknown41;
u32 lda_factors[6];
u32 max_num_merge_cand;
};
struct mcu_msg_create_channel {
struct mcu_msg_header header;
u32 user_id;
u32 *blob;
size_t blob_size;
u32 blob_mcu_addr;
u32 ep1_addr;
};
struct mcu_msg_create_channel_response {
struct mcu_msg_header header;
u32 channel_id;
u32 user_id;
u32 options;
u32 num_core;
u32 num_ref_idx_l0;
u32 num_ref_idx_l1;
u32 int_buffers_count;
u32 int_buffers_size;
u32 rec_buffers_count;
u32 rec_buffers_size;
u32 reserved;
u32 error_code;
};
struct mcu_msg_destroy_channel {
struct mcu_msg_header header;
u32 channel_id;
};
struct mcu_msg_destroy_channel_response {
struct mcu_msg_header header;
u32 channel_id;
};
struct mcu_msg_push_buffers_internal_buffer {
u32 dma_addr;
u32 mcu_addr;
u32 size;
};
struct mcu_msg_push_buffers_internal {
struct mcu_msg_header header;
u32 channel_id;
size_t num_buffers;
struct mcu_msg_push_buffers_internal_buffer buffer[] __counted_by(num_buffers);
};
struct mcu_msg_put_stream_buffer {
struct mcu_msg_header header;
u32 channel_id;
u32 dma_addr;
u32 mcu_addr;
u32 size;
u32 offset;
u64 dst_handle;
};
struct mcu_msg_encode_frame {
struct mcu_msg_header header;
u32 channel_id;
u32 reserved;
u32 encoding_options;
#define AL_OPT_USE_QP_TABLE BIT(0)
#define AL_OPT_FORCE_LOAD BIT(1)
#define AL_OPT_USE_L2 BIT(2)
#define AL_OPT_DISABLE_INTRA BIT(3)
#define AL_OPT_DEPENDENT_SLICES BIT(4)
s16 pps_qp;
u16 padding;
u64 user_param;
u64 src_handle;
u32 request_options;
#define AL_OPT_SCENE_CHANGE BIT(0)
#define AL_OPT_RESTART_GOP BIT(1)
#define AL_OPT_USE_LONG_TERM BIT(2)
#define AL_OPT_UPDATE_PARAMS BIT(3)
/* u32 scene_change_delay (optional) */
/* rate control param (optional) */
/* gop param (optional) */
/* dynamic resolution params (optional) */
u32 src_y;
u32 src_uv;
u32 is_10_bit;
u32 stride;
u32 format;
u32 ep2;
u64 ep2_v;
};
struct mcu_msg_encode_frame_response {
struct mcu_msg_header header;
u32 channel_id;
u64 dst_handle; /* see mcu_msg_put_stream_buffer */
u64 user_param; /* see mcu_msg_encode_frame */
u64 src_handle; /* see mcu_msg_encode_frame */
u16 skip;
u16 is_ref;
u32 initial_removal_delay;
u32 dpb_output_delay;
u32 size;
u32 frame_tag_size;
s32 stuffing;
s32 filler;
u16 num_column;
u16 num_row;
u16 qp;
u8 num_ref_idx_l0;
u8 num_ref_idx_l1;
u32 partition_table_offset;
s32 partition_table_size;
u32 sum_complex;
s32 tile_width[4];
s32 tile_height[22];
u32 error_code;
u32 slice_type;
#define AL_ENC_SLICE_TYPE_B 0
#define AL_ENC_SLICE_TYPE_P 1
#define AL_ENC_SLICE_TYPE_I 2
u32 pic_struct;
u8 is_idr;
u8 is_first_slice;
u8 is_last_slice;
u8 reserved;
u16 pps_qp;
u16 reserved1;
u32 reserved2;
u32 reserved3;
u32 reserved4;
u32 reserved5;
u32 reserved6;
};
union mcu_msg_response {
struct mcu_msg_header header;
struct mcu_msg_init_response init;
struct mcu_msg_create_channel_response create_channel;
struct mcu_msg_destroy_channel_response destroy_channel;
struct mcu_msg_encode_frame_response encode_frame;
};
ssize_t allegro_encode_config_blob(u32 *dst, struct create_channel_param *param);
ssize_t allegro_decode_config_blob(struct create_channel_param *param,
struct mcu_msg_create_channel_response *msg,
u32 *src);
int allegro_decode_mail(void *msg, u32 *src);
ssize_t allegro_encode_mail(u32 *dst, void *msg);
#endif
@@ -0,0 +1,605 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2019 Pengutronix, Michael Tretter <kernel@pengutronix.de>
*
* Convert NAL units between raw byte sequence payloads (RBSP) and C structs
*
* The conversion is defined in "ITU-T Rec. H.264 (04/2017) Advanced video
* coding for generic audiovisual services". Decoder drivers may use the
* parser to parse RBSP from encoded streams and configure the hardware, if
* the hardware is not able to parse RBSP itself. Encoder drivers may use the
* generator to generate the RBSP for SPS/PPS nal units and add them to the
* encoded stream if the hardware does not generate the units.
*/
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/string.h>
#include <linux/v4l2-controls.h>
#include <linux/device.h>
#include <linux/export.h>
#include <linux/log2.h>
#include "nal-h264.h"
#include "nal-rbsp.h"
/*
* See Rec. ITU-T H.264 (04/2017) Table 7-1 - NAL unit type codes, syntax
* element categories, and NAL unit type classes
*/
enum nal_unit_type {
SEQUENCE_PARAMETER_SET = 7,
PICTURE_PARAMETER_SET = 8,
FILLER_DATA = 12,
};
static void nal_h264_write_start_code_prefix(struct rbsp *rbsp)
{
u8 *p = rbsp->data + DIV_ROUND_UP(rbsp->pos, 8);
int i = 4;
if (DIV_ROUND_UP(rbsp->pos, 8) + i > rbsp->size) {
rbsp->error = -EINVAL;
return;
}
p[0] = 0x00;
p[1] = 0x00;
p[2] = 0x00;
p[3] = 0x01;
rbsp->pos += i * 8;
}
static void nal_h264_read_start_code_prefix(struct rbsp *rbsp)
{
u8 *p = rbsp->data + DIV_ROUND_UP(rbsp->pos, 8);
int i = 4;
if (DIV_ROUND_UP(rbsp->pos, 8) + i > rbsp->size) {
rbsp->error = -EINVAL;
return;
}
if (p[0] != 0x00 || p[1] != 0x00 || p[2] != 0x00 || p[3] != 0x01) {
rbsp->error = -EINVAL;
return;
}
rbsp->pos += i * 8;
}
static void nal_h264_write_filler_data(struct rbsp *rbsp)
{
u8 *p = rbsp->data + DIV_ROUND_UP(rbsp->pos, 8);
int i;
/* Keep 1 byte extra for terminating the NAL unit */
i = rbsp->size - DIV_ROUND_UP(rbsp->pos, 8) - 1;
memset(p, 0xff, i);
rbsp->pos += i * 8;
}
static void nal_h264_read_filler_data(struct rbsp *rbsp)
{
u8 *p = rbsp->data + DIV_ROUND_UP(rbsp->pos, 8);
while (*p == 0xff) {
if (DIV_ROUND_UP(rbsp->pos, 8) > rbsp->size) {
rbsp->error = -EINVAL;
return;
}
p++;
rbsp->pos += 8;
}
}
static void nal_h264_rbsp_hrd_parameters(struct rbsp *rbsp,
struct nal_h264_hrd_parameters *hrd)
{
unsigned int i;
if (!hrd) {
rbsp->error = -EINVAL;
return;
}
rbsp_uev(rbsp, &hrd->cpb_cnt_minus1);
rbsp_bits(rbsp, 4, &hrd->bit_rate_scale);
rbsp_bits(rbsp, 4, &hrd->cpb_size_scale);
for (i = 0; i <= hrd->cpb_cnt_minus1; i++) {
rbsp_uev(rbsp, &hrd->bit_rate_value_minus1[i]);
rbsp_uev(rbsp, &hrd->cpb_size_value_minus1[i]);
rbsp_bit(rbsp, &hrd->cbr_flag[i]);
}
rbsp_bits(rbsp, 5, &hrd->initial_cpb_removal_delay_length_minus1);
rbsp_bits(rbsp, 5, &hrd->cpb_removal_delay_length_minus1);
rbsp_bits(rbsp, 5, &hrd->dpb_output_delay_length_minus1);
rbsp_bits(rbsp, 5, &hrd->time_offset_length);
}
static void nal_h264_rbsp_vui_parameters(struct rbsp *rbsp,
struct nal_h264_vui_parameters *vui)
{
if (!vui) {
rbsp->error = -EINVAL;
return;
}
rbsp_bit(rbsp, &vui->aspect_ratio_info_present_flag);
if (vui->aspect_ratio_info_present_flag) {
rbsp_bits(rbsp, 8, &vui->aspect_ratio_idc);
if (vui->aspect_ratio_idc == 255) {
rbsp_bits(rbsp, 16, &vui->sar_width);
rbsp_bits(rbsp, 16, &vui->sar_height);
}
}
rbsp_bit(rbsp, &vui->overscan_info_present_flag);
if (vui->overscan_info_present_flag)
rbsp_bit(rbsp, &vui->overscan_appropriate_flag);
rbsp_bit(rbsp, &vui->video_signal_type_present_flag);
if (vui->video_signal_type_present_flag) {
rbsp_bits(rbsp, 3, &vui->video_format);
rbsp_bit(rbsp, &vui->video_full_range_flag);
rbsp_bit(rbsp, &vui->colour_description_present_flag);
if (vui->colour_description_present_flag) {
rbsp_bits(rbsp, 8, &vui->colour_primaries);
rbsp_bits(rbsp, 8, &vui->transfer_characteristics);
rbsp_bits(rbsp, 8, &vui->matrix_coefficients);
}
}
rbsp_bit(rbsp, &vui->chroma_loc_info_present_flag);
if (vui->chroma_loc_info_present_flag) {
rbsp_uev(rbsp, &vui->chroma_sample_loc_type_top_field);
rbsp_uev(rbsp, &vui->chroma_sample_loc_type_bottom_field);
}
rbsp_bit(rbsp, &vui->timing_info_present_flag);
if (vui->timing_info_present_flag) {
rbsp_bits(rbsp, 32, &vui->num_units_in_tick);
rbsp_bits(rbsp, 32, &vui->time_scale);
rbsp_bit(rbsp, &vui->fixed_frame_rate_flag);
}
rbsp_bit(rbsp, &vui->nal_hrd_parameters_present_flag);
if (vui->nal_hrd_parameters_present_flag)
nal_h264_rbsp_hrd_parameters(rbsp, &vui->nal_hrd_parameters);
rbsp_bit(rbsp, &vui->vcl_hrd_parameters_present_flag);
if (vui->vcl_hrd_parameters_present_flag)
nal_h264_rbsp_hrd_parameters(rbsp, &vui->vcl_hrd_parameters);
if (vui->nal_hrd_parameters_present_flag ||
vui->vcl_hrd_parameters_present_flag)
rbsp_bit(rbsp, &vui->low_delay_hrd_flag);
rbsp_bit(rbsp, &vui->pic_struct_present_flag);
rbsp_bit(rbsp, &vui->bitstream_restriction_flag);
if (vui->bitstream_restriction_flag) {
rbsp_bit(rbsp, &vui->motion_vectors_over_pic_boundaries_flag);
rbsp_uev(rbsp, &vui->max_bytes_per_pic_denom);
rbsp_uev(rbsp, &vui->max_bits_per_mb_denom);
rbsp_uev(rbsp, &vui->log2_max_mv_length_horizontal);
rbsp_uev(rbsp, &vui->log21_max_mv_length_vertical);
rbsp_uev(rbsp, &vui->max_num_reorder_frames);
rbsp_uev(rbsp, &vui->max_dec_frame_buffering);
}
}
static void nal_h264_rbsp_sps(struct rbsp *rbsp, struct nal_h264_sps *sps)
{
unsigned int i;
if (!sps) {
rbsp->error = -EINVAL;
return;
}
rbsp_bits(rbsp, 8, &sps->profile_idc);
rbsp_bit(rbsp, &sps->constraint_set0_flag);
rbsp_bit(rbsp, &sps->constraint_set1_flag);
rbsp_bit(rbsp, &sps->constraint_set2_flag);
rbsp_bit(rbsp, &sps->constraint_set3_flag);
rbsp_bit(rbsp, &sps->constraint_set4_flag);
rbsp_bit(rbsp, &sps->constraint_set5_flag);
rbsp_bits(rbsp, 2, &sps->reserved_zero_2bits);
rbsp_bits(rbsp, 8, &sps->level_idc);
rbsp_uev(rbsp, &sps->seq_parameter_set_id);
if (sps->profile_idc == 100 || sps->profile_idc == 110 ||
sps->profile_idc == 122 || sps->profile_idc == 244 ||
sps->profile_idc == 44 || sps->profile_idc == 83 ||
sps->profile_idc == 86 || sps->profile_idc == 118 ||
sps->profile_idc == 128 || sps->profile_idc == 138 ||
sps->profile_idc == 139 || sps->profile_idc == 134 ||
sps->profile_idc == 135) {
rbsp_uev(rbsp, &sps->chroma_format_idc);
if (sps->chroma_format_idc == 3)
rbsp_bit(rbsp, &sps->separate_colour_plane_flag);
rbsp_uev(rbsp, &sps->bit_depth_luma_minus8);
rbsp_uev(rbsp, &sps->bit_depth_chroma_minus8);
rbsp_bit(rbsp, &sps->qpprime_y_zero_transform_bypass_flag);
rbsp_bit(rbsp, &sps->seq_scaling_matrix_present_flag);
if (sps->seq_scaling_matrix_present_flag)
rbsp->error = -EINVAL;
}
rbsp_uev(rbsp, &sps->log2_max_frame_num_minus4);
rbsp_uev(rbsp, &sps->pic_order_cnt_type);
switch (sps->pic_order_cnt_type) {
case 0:
rbsp_uev(rbsp, &sps->log2_max_pic_order_cnt_lsb_minus4);
break;
case 1:
rbsp_bit(rbsp, &sps->delta_pic_order_always_zero_flag);
rbsp_sev(rbsp, &sps->offset_for_non_ref_pic);
rbsp_sev(rbsp, &sps->offset_for_top_to_bottom_field);
rbsp_uev(rbsp, &sps->num_ref_frames_in_pic_order_cnt_cycle);
for (i = 0; i < sps->num_ref_frames_in_pic_order_cnt_cycle; i++)
rbsp_sev(rbsp, &sps->offset_for_ref_frame[i]);
break;
default:
rbsp->error = -EINVAL;
break;
}
rbsp_uev(rbsp, &sps->max_num_ref_frames);
rbsp_bit(rbsp, &sps->gaps_in_frame_num_value_allowed_flag);
rbsp_uev(rbsp, &sps->pic_width_in_mbs_minus1);
rbsp_uev(rbsp, &sps->pic_height_in_map_units_minus1);
rbsp_bit(rbsp, &sps->frame_mbs_only_flag);
if (!sps->frame_mbs_only_flag)
rbsp_bit(rbsp, &sps->mb_adaptive_frame_field_flag);
rbsp_bit(rbsp, &sps->direct_8x8_inference_flag);
rbsp_bit(rbsp, &sps->frame_cropping_flag);
if (sps->frame_cropping_flag) {
rbsp_uev(rbsp, &sps->crop_left);
rbsp_uev(rbsp, &sps->crop_right);
rbsp_uev(rbsp, &sps->crop_top);
rbsp_uev(rbsp, &sps->crop_bottom);
}
rbsp_bit(rbsp, &sps->vui_parameters_present_flag);
if (sps->vui_parameters_present_flag)
nal_h264_rbsp_vui_parameters(rbsp, &sps->vui);
}
static void nal_h264_rbsp_pps(struct rbsp *rbsp, struct nal_h264_pps *pps)
{
int i;
rbsp_uev(rbsp, &pps->pic_parameter_set_id);
rbsp_uev(rbsp, &pps->seq_parameter_set_id);
rbsp_bit(rbsp, &pps->entropy_coding_mode_flag);
rbsp_bit(rbsp, &pps->bottom_field_pic_order_in_frame_present_flag);
rbsp_uev(rbsp, &pps->num_slice_groups_minus1);
if (pps->num_slice_groups_minus1 > 0) {
rbsp_uev(rbsp, &pps->slice_group_map_type);
switch (pps->slice_group_map_type) {
case 0:
for (i = 0; i < pps->num_slice_groups_minus1; i++)
rbsp_uev(rbsp, &pps->run_length_minus1[i]);
break;
case 2:
for (i = 0; i < pps->num_slice_groups_minus1; i++) {
rbsp_uev(rbsp, &pps->top_left[i]);
rbsp_uev(rbsp, &pps->bottom_right[i]);
}
break;
case 3: case 4: case 5:
rbsp_bit(rbsp, &pps->slice_group_change_direction_flag);
rbsp_uev(rbsp, &pps->slice_group_change_rate_minus1);
break;
case 6:
rbsp_uev(rbsp, &pps->pic_size_in_map_units_minus1);
for (i = 0; i < pps->pic_size_in_map_units_minus1; i++)
rbsp_bits(rbsp,
order_base_2(pps->num_slice_groups_minus1 + 1),
&pps->slice_group_id[i]);
break;
default:
break;
}
}
rbsp_uev(rbsp, &pps->num_ref_idx_l0_default_active_minus1);
rbsp_uev(rbsp, &pps->num_ref_idx_l1_default_active_minus1);
rbsp_bit(rbsp, &pps->weighted_pred_flag);
rbsp_bits(rbsp, 2, &pps->weighted_bipred_idc);
rbsp_sev(rbsp, &pps->pic_init_qp_minus26);
rbsp_sev(rbsp, &pps->pic_init_qs_minus26);
rbsp_sev(rbsp, &pps->chroma_qp_index_offset);
rbsp_bit(rbsp, &pps->deblocking_filter_control_present_flag);
rbsp_bit(rbsp, &pps->constrained_intra_pred_flag);
rbsp_bit(rbsp, &pps->redundant_pic_cnt_present_flag);
if (/* more_rbsp_data() */ false) {
rbsp_bit(rbsp, &pps->transform_8x8_mode_flag);
rbsp_bit(rbsp, &pps->pic_scaling_matrix_present_flag);
if (pps->pic_scaling_matrix_present_flag)
rbsp->error = -EINVAL;
rbsp_sev(rbsp, &pps->second_chroma_qp_index_offset);
}
}
/**
* nal_h264_write_sps() - Write SPS NAL unit into RBSP format
* @dev: device pointer
* @dest: the buffer that is filled with RBSP data
* @n: maximum size of @dest in bytes
* @sps: &struct nal_h264_sps to convert to RBSP
*
* Convert @sps to RBSP data and write it into @dest.
*
* The size of the SPS NAL unit is not known in advance and this function will
* fail, if @dest does not hold sufficient space for the SPS NAL unit.
*
* Return: number of bytes written to @dest or negative error code
*/
ssize_t nal_h264_write_sps(const struct device *dev,
void *dest, size_t n, struct nal_h264_sps *sps)
{
struct rbsp rbsp;
unsigned int forbidden_zero_bit = 0;
unsigned int nal_ref_idc = 0;
unsigned int nal_unit_type = SEQUENCE_PARAMETER_SET;
if (!dest)
return -EINVAL;
rbsp_init(&rbsp, dest, n, &write);
nal_h264_write_start_code_prefix(&rbsp);
rbsp_bit(&rbsp, &forbidden_zero_bit);
rbsp_bits(&rbsp, 2, &nal_ref_idc);
rbsp_bits(&rbsp, 5, &nal_unit_type);
nal_h264_rbsp_sps(&rbsp, sps);
rbsp_trailing_bits(&rbsp);
if (rbsp.error)
return rbsp.error;
return DIV_ROUND_UP(rbsp.pos, 8);
}
EXPORT_SYMBOL_GPL(nal_h264_write_sps);
/**
* nal_h264_read_sps() - Read SPS NAL unit from RBSP format
* @dev: device pointer
* @sps: the &struct nal_h264_sps to fill from the RBSP data
* @src: the buffer that contains the RBSP data
* @n: size of @src in bytes
*
* Read RBSP data from @src and use it to fill @sps.
*
* Return: number of bytes read from @src or negative error code
*/
ssize_t nal_h264_read_sps(const struct device *dev,
struct nal_h264_sps *sps, void *src, size_t n)
{
struct rbsp rbsp;
unsigned int forbidden_zero_bit;
unsigned int nal_ref_idc;
unsigned int nal_unit_type;
if (!src)
return -EINVAL;
rbsp_init(&rbsp, src, n, &read);
nal_h264_read_start_code_prefix(&rbsp);
rbsp_bit(&rbsp, &forbidden_zero_bit);
rbsp_bits(&rbsp, 2, &nal_ref_idc);
rbsp_bits(&rbsp, 5, &nal_unit_type);
if (rbsp.error ||
forbidden_zero_bit != 0 ||
nal_ref_idc != 0 ||
nal_unit_type != SEQUENCE_PARAMETER_SET)
return -EINVAL;
nal_h264_rbsp_sps(&rbsp, sps);
rbsp_trailing_bits(&rbsp);
if (rbsp.error)
return rbsp.error;
return DIV_ROUND_UP(rbsp.pos, 8);
}
EXPORT_SYMBOL_GPL(nal_h264_read_sps);
/**
* nal_h264_write_pps() - Write PPS NAL unit into RBSP format
* @dev: device pointer
* @dest: the buffer that is filled with RBSP data
* @n: maximum size of @dest in bytes
* @pps: &struct nal_h264_pps to convert to RBSP
*
* Convert @pps to RBSP data and write it into @dest.
*
* The size of the PPS NAL unit is not known in advance and this function will
* fail, if @dest does not hold sufficient space for the PPS NAL unit.
*
* Return: number of bytes written to @dest or negative error code
*/
ssize_t nal_h264_write_pps(const struct device *dev,
void *dest, size_t n, struct nal_h264_pps *pps)
{
struct rbsp rbsp;
unsigned int forbidden_zero_bit = 0;
unsigned int nal_ref_idc = 0;
unsigned int nal_unit_type = PICTURE_PARAMETER_SET;
if (!dest)
return -EINVAL;
rbsp_init(&rbsp, dest, n, &write);
nal_h264_write_start_code_prefix(&rbsp);
/* NAL unit header */
rbsp_bit(&rbsp, &forbidden_zero_bit);
rbsp_bits(&rbsp, 2, &nal_ref_idc);
rbsp_bits(&rbsp, 5, &nal_unit_type);
nal_h264_rbsp_pps(&rbsp, pps);
rbsp_trailing_bits(&rbsp);
if (rbsp.error)
return rbsp.error;
return DIV_ROUND_UP(rbsp.pos, 8);
}
EXPORT_SYMBOL_GPL(nal_h264_write_pps);
/**
* nal_h264_read_pps() - Read PPS NAL unit from RBSP format
* @dev: device pointer
* @pps: the &struct nal_h264_pps to fill from the RBSP data
* @src: the buffer that contains the RBSP data
* @n: size of @src in bytes
*
* Read RBSP data from @src and use it to fill @pps.
*
* Return: number of bytes read from @src or negative error code
*/
ssize_t nal_h264_read_pps(const struct device *dev,
struct nal_h264_pps *pps, void *src, size_t n)
{
struct rbsp rbsp;
if (!src)
return -EINVAL;
rbsp_init(&rbsp, src, n, &read);
nal_h264_read_start_code_prefix(&rbsp);
/* NAL unit header */
rbsp.pos += 8;
nal_h264_rbsp_pps(&rbsp, pps);
rbsp_trailing_bits(&rbsp);
if (rbsp.error)
return rbsp.error;
return DIV_ROUND_UP(rbsp.pos, 8);
}
EXPORT_SYMBOL_GPL(nal_h264_read_pps);
/**
* nal_h264_write_filler() - Write filler data RBSP
* @dev: device pointer
* @dest: buffer to fill with filler data
* @n: size of the buffer to fill with filler data
*
* Write a filler data RBSP to @dest with a size of @n bytes and return the
* number of written filler data bytes.
*
* Use this function to generate dummy data in an RBSP data stream that can be
* safely ignored by h264 decoders.
*
* The RBSP format of the filler data is specified in Rec. ITU-T H.264
* (04/2017) 7.3.2.7 Filler data RBSP syntax.
*
* Return: number of filler data bytes (including marker) or negative error
*/
ssize_t nal_h264_write_filler(const struct device *dev, void *dest, size_t n)
{
struct rbsp rbsp;
unsigned int forbidden_zero_bit = 0;
unsigned int nal_ref_idc = 0;
unsigned int nal_unit_type = FILLER_DATA;
if (!dest)
return -EINVAL;
rbsp_init(&rbsp, dest, n, &write);
nal_h264_write_start_code_prefix(&rbsp);
rbsp_bit(&rbsp, &forbidden_zero_bit);
rbsp_bits(&rbsp, 2, &nal_ref_idc);
rbsp_bits(&rbsp, 5, &nal_unit_type);
nal_h264_write_filler_data(&rbsp);
rbsp_trailing_bits(&rbsp);
return DIV_ROUND_UP(rbsp.pos, 8);
}
EXPORT_SYMBOL_GPL(nal_h264_write_filler);
/**
* nal_h264_read_filler() - Read filler data RBSP
* @dev: device pointer
* @src: buffer with RBSP data that is read
* @n: maximum size of src that shall be read
*
* Read a filler data RBSP from @src up to a maximum size of @n bytes and
* return the size of the filler data in bytes including the marker.
*
* This function is used to parse filler data and skip the respective bytes in
* the RBSP data.
*
* The RBSP format of the filler data is specified in Rec. ITU-T H.264
* (04/2017) 7.3.2.7 Filler data RBSP syntax.
*
* Return: number of filler data bytes (including marker) or negative error
*/
ssize_t nal_h264_read_filler(const struct device *dev, void *src, size_t n)
{
struct rbsp rbsp;
unsigned int forbidden_zero_bit;
unsigned int nal_ref_idc;
unsigned int nal_unit_type;
if (!src)
return -EINVAL;
rbsp_init(&rbsp, src, n, &read);
nal_h264_read_start_code_prefix(&rbsp);
rbsp_bit(&rbsp, &forbidden_zero_bit);
rbsp_bits(&rbsp, 2, &nal_ref_idc);
rbsp_bits(&rbsp, 5, &nal_unit_type);
if (rbsp.error)
return rbsp.error;
if (forbidden_zero_bit != 0 ||
nal_ref_idc != 0 ||
nal_unit_type != FILLER_DATA)
return -EINVAL;
nal_h264_read_filler_data(&rbsp);
rbsp_trailing_bits(&rbsp);
if (rbsp.error)
return rbsp.error;
return DIV_ROUND_UP(rbsp.pos, 8);
}
EXPORT_SYMBOL_GPL(nal_h264_read_filler);
@@ -0,0 +1,404 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) 2019 Pengutronix, Michael Tretter <kernel@pengutronix.de>
*
* Convert NAL units between raw byte sequence payloads (RBSP) and C structs.
*/
#ifndef __NAL_H264_H__
#define __NAL_H264_H__
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/v4l2-controls.h>
#include <linux/videodev2.h>
/*
* struct nal_h264_hrd_parameters - HRD parameters
*
* C struct representation of the sequence parameter set NAL unit as defined by
* Rec. ITU-T H.264 (04/2017) E.1.2 HRD parameters syntax.
*/
struct nal_h264_hrd_parameters {
unsigned int cpb_cnt_minus1;
unsigned int bit_rate_scale;
unsigned int cpb_size_scale;
struct {
int bit_rate_value_minus1[16];
int cpb_size_value_minus1[16];
unsigned int cbr_flag[16];
};
unsigned int initial_cpb_removal_delay_length_minus1;
unsigned int cpb_removal_delay_length_minus1;
unsigned int dpb_output_delay_length_minus1;
unsigned int time_offset_length;
};
/*
* struct nal_h264_vui_parameters - VUI parameters
*
* C struct representation of the VUI parameters as defined by Rec. ITU-T
* H.264 (04/2017) E.1.1 VUI parameters syntax.
*/
struct nal_h264_vui_parameters {
unsigned int aspect_ratio_info_present_flag;
struct {
unsigned int aspect_ratio_idc;
unsigned int sar_width;
unsigned int sar_height;
};
unsigned int overscan_info_present_flag;
unsigned int overscan_appropriate_flag;
unsigned int video_signal_type_present_flag;
struct {
unsigned int video_format;
unsigned int video_full_range_flag;
unsigned int colour_description_present_flag;
struct {
unsigned int colour_primaries;
unsigned int transfer_characteristics;
unsigned int matrix_coefficients;
};
};
unsigned int chroma_loc_info_present_flag;
struct {
unsigned int chroma_sample_loc_type_top_field;
unsigned int chroma_sample_loc_type_bottom_field;
};
unsigned int timing_info_present_flag;
struct {
unsigned int num_units_in_tick;
unsigned int time_scale;
unsigned int fixed_frame_rate_flag;
};
unsigned int nal_hrd_parameters_present_flag;
struct nal_h264_hrd_parameters nal_hrd_parameters;
unsigned int vcl_hrd_parameters_present_flag;
struct nal_h264_hrd_parameters vcl_hrd_parameters;
unsigned int low_delay_hrd_flag;
unsigned int pic_struct_present_flag;
unsigned int bitstream_restriction_flag;
struct {
unsigned int motion_vectors_over_pic_boundaries_flag;
unsigned int max_bytes_per_pic_denom;
unsigned int max_bits_per_mb_denom;
unsigned int log2_max_mv_length_horizontal;
unsigned int log21_max_mv_length_vertical;
unsigned int max_num_reorder_frames;
unsigned int max_dec_frame_buffering;
};
};
/*
* struct nal_h264_sps - Sequence parameter set
*
* C struct representation of the sequence parameter set NAL unit as defined by
* Rec. ITU-T H.264 (04/2017) 7.3.2.1.1 Sequence parameter set data syntax.
*/
struct nal_h264_sps {
unsigned int profile_idc;
unsigned int constraint_set0_flag;
unsigned int constraint_set1_flag;
unsigned int constraint_set2_flag;
unsigned int constraint_set3_flag;
unsigned int constraint_set4_flag;
unsigned int constraint_set5_flag;
unsigned int reserved_zero_2bits;
unsigned int level_idc;
unsigned int seq_parameter_set_id;
struct {
unsigned int chroma_format_idc;
unsigned int separate_colour_plane_flag;
unsigned int bit_depth_luma_minus8;
unsigned int bit_depth_chroma_minus8;
unsigned int qpprime_y_zero_transform_bypass_flag;
unsigned int seq_scaling_matrix_present_flag;
};
unsigned int log2_max_frame_num_minus4;
unsigned int pic_order_cnt_type;
union {
unsigned int log2_max_pic_order_cnt_lsb_minus4;
struct {
unsigned int delta_pic_order_always_zero_flag;
int offset_for_non_ref_pic;
int offset_for_top_to_bottom_field;
unsigned int num_ref_frames_in_pic_order_cnt_cycle;
int offset_for_ref_frame[255];
};
};
unsigned int max_num_ref_frames;
unsigned int gaps_in_frame_num_value_allowed_flag;
unsigned int pic_width_in_mbs_minus1;
unsigned int pic_height_in_map_units_minus1;
unsigned int frame_mbs_only_flag;
unsigned int mb_adaptive_frame_field_flag;
unsigned int direct_8x8_inference_flag;
unsigned int frame_cropping_flag;
struct {
unsigned int crop_left;
unsigned int crop_right;
unsigned int crop_top;
unsigned int crop_bottom;
};
unsigned int vui_parameters_present_flag;
struct nal_h264_vui_parameters vui;
};
/*
* struct nal_h264_pps - Picture parameter set
*
* C struct representation of the picture parameter set NAL unit as defined by
* Rec. ITU-T H.264 (04/2017) 7.3.2.2 Picture parameter set RBSP syntax.
*/
struct nal_h264_pps {
unsigned int pic_parameter_set_id;
unsigned int seq_parameter_set_id;
unsigned int entropy_coding_mode_flag;
unsigned int bottom_field_pic_order_in_frame_present_flag;
unsigned int num_slice_groups_minus1;
unsigned int slice_group_map_type;
union {
unsigned int run_length_minus1[8];
struct {
unsigned int top_left[8];
unsigned int bottom_right[8];
};
struct {
unsigned int slice_group_change_direction_flag;
unsigned int slice_group_change_rate_minus1;
};
struct {
unsigned int pic_size_in_map_units_minus1;
unsigned int slice_group_id[8];
};
};
unsigned int num_ref_idx_l0_default_active_minus1;
unsigned int num_ref_idx_l1_default_active_minus1;
unsigned int weighted_pred_flag;
unsigned int weighted_bipred_idc;
int pic_init_qp_minus26;
int pic_init_qs_minus26;
int chroma_qp_index_offset;
unsigned int deblocking_filter_control_present_flag;
unsigned int constrained_intra_pred_flag;
unsigned int redundant_pic_cnt_present_flag;
struct {
unsigned int transform_8x8_mode_flag;
unsigned int pic_scaling_matrix_present_flag;
int second_chroma_qp_index_offset;
};
};
/**
* nal_h264_profile() - Get profile_idc for v4l2 h264 profile
* @profile: the profile as &enum v4l2_mpeg_video_h264_profile
*
* Convert the &enum v4l2_mpeg_video_h264_profile to profile_idc as specified
* in Rec. ITU-T H.264 (04/2017) A.2.
*
* Return: the profile_idc for the passed level
*/
static inline int nal_h264_profile(enum v4l2_mpeg_video_h264_profile profile)
{
switch (profile) {
case V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE:
return 66;
case V4L2_MPEG_VIDEO_H264_PROFILE_MAIN:
return 77;
case V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED:
return 88;
case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH:
return 100;
default:
return -EINVAL;
}
}
/**
* nal_h264_level() - Get level_idc for v4l2 h264 level
* @level: the level as &enum v4l2_mpeg_video_h264_level
*
* Convert the &enum v4l2_mpeg_video_h264_level to level_idc as specified in
* Rec. ITU-T H.264 (04/2017) A.3.2.
*
* Return: the level_idc for the passed level
*/
static inline int nal_h264_level(enum v4l2_mpeg_video_h264_level level)
{
switch (level) {
case V4L2_MPEG_VIDEO_H264_LEVEL_1_0:
return 10;
case V4L2_MPEG_VIDEO_H264_LEVEL_1B:
return 9;
case V4L2_MPEG_VIDEO_H264_LEVEL_1_1:
return 11;
case V4L2_MPEG_VIDEO_H264_LEVEL_1_2:
return 12;
case V4L2_MPEG_VIDEO_H264_LEVEL_1_3:
return 13;
case V4L2_MPEG_VIDEO_H264_LEVEL_2_0:
return 20;
case V4L2_MPEG_VIDEO_H264_LEVEL_2_1:
return 21;
case V4L2_MPEG_VIDEO_H264_LEVEL_2_2:
return 22;
case V4L2_MPEG_VIDEO_H264_LEVEL_3_0:
return 30;
case V4L2_MPEG_VIDEO_H264_LEVEL_3_1:
return 31;
case V4L2_MPEG_VIDEO_H264_LEVEL_3_2:
return 32;
case V4L2_MPEG_VIDEO_H264_LEVEL_4_0:
return 40;
case V4L2_MPEG_VIDEO_H264_LEVEL_4_1:
return 41;
case V4L2_MPEG_VIDEO_H264_LEVEL_4_2:
return 42;
case V4L2_MPEG_VIDEO_H264_LEVEL_5_0:
return 50;
case V4L2_MPEG_VIDEO_H264_LEVEL_5_1:
return 51;
default:
return -EINVAL;
}
}
/**
* nal_h264_full_range() - Get video_full_range_flag for v4l2 quantization
* @quantization: the quantization type as &enum v4l2_quantization
*
* Convert the &enum v4l2_quantization to video_full_range_flag as specified in
* Rec. ITU-T H.264 (04/2017) E.2.1.
*
* Return: the video_full_range_flag value for the passed quantization
*/
static inline int nal_h264_full_range(enum v4l2_quantization quantization)
{
switch (quantization) {
case V4L2_QUANTIZATION_FULL_RANGE:
return 1;
case V4L2_QUANTIZATION_LIM_RANGE:
return 0;
default:
break;
}
return 0;
}
/**
* nal_h264_color_primaries() - Get color_primaries for v4l2 colorspace
* @colorspace: the color space as &enum v4l2_colorspace
*
* Convert the &enum v4l2_colorspace to color_primaries as specified in
* Rec. ITU-T H.264 (04/2017) E.2.1.
*
* Return: the color_primaries value for the passed colorspace
*/
static inline int nal_h264_color_primaries(enum v4l2_colorspace colorspace)
{
switch (colorspace) {
case V4L2_COLORSPACE_SMPTE170M:
return 6;
case V4L2_COLORSPACE_SMPTE240M:
return 7;
case V4L2_COLORSPACE_REC709:
return 1;
case V4L2_COLORSPACE_470_SYSTEM_M:
return 4;
case V4L2_COLORSPACE_JPEG:
case V4L2_COLORSPACE_SRGB:
case V4L2_COLORSPACE_470_SYSTEM_BG:
return 5;
case V4L2_COLORSPACE_BT2020:
return 9;
case V4L2_COLORSPACE_DEFAULT:
case V4L2_COLORSPACE_OPRGB:
case V4L2_COLORSPACE_RAW:
case V4L2_COLORSPACE_DCI_P3:
default:
return 2;
}
}
/**
* nal_h264_transfer_characteristics() - Get transfer_characteristics for v4l2 xfer_func
* @colorspace: the color space as &enum v4l2_colorspace
* @xfer_func: the transfer function as &enum v4l2_xfer_func
*
* Convert the &enum v4l2_xfer_func to transfer_characteristics as specified in
* Rec. ITU-T H.264 (04/2017) E.2.1.
*
* Return: the transfer_characteristics value for the passed transfer function
*/
static inline int nal_h264_transfer_characteristics(enum v4l2_colorspace colorspace,
enum v4l2_xfer_func xfer_func)
{
if (xfer_func == V4L2_XFER_FUNC_DEFAULT)
xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(colorspace);
switch (xfer_func) {
case V4L2_XFER_FUNC_709:
return 6;
case V4L2_XFER_FUNC_SMPTE2084:
return 16;
case V4L2_XFER_FUNC_SRGB:
case V4L2_XFER_FUNC_OPRGB:
case V4L2_XFER_FUNC_NONE:
case V4L2_XFER_FUNC_DCI_P3:
case V4L2_XFER_FUNC_SMPTE240M:
default:
return 2;
}
}
/**
* nal_h264_matrix_coeffs() - Get matrix_coefficients for v4l2 v4l2_ycbcr_encoding
* @colorspace: the color space as &enum v4l2_colorspace
* @ycbcr_encoding: the ycbcr encoding as &enum v4l2_ycbcr_encoding
*
* Convert the &enum v4l2_ycbcr_encoding to matrix_coefficients as specified in
* Rec. ITU-T H.264 (04/2017) E.2.1.
*
* Return: the matrix_coefficients value for the passed encoding
*/
static inline int nal_h264_matrix_coeffs(enum v4l2_colorspace colorspace,
enum v4l2_ycbcr_encoding ycbcr_encoding)
{
if (ycbcr_encoding == V4L2_YCBCR_ENC_DEFAULT)
ycbcr_encoding = V4L2_MAP_YCBCR_ENC_DEFAULT(colorspace);
switch (ycbcr_encoding) {
case V4L2_YCBCR_ENC_601:
case V4L2_YCBCR_ENC_XV601:
return 5;
case V4L2_YCBCR_ENC_709:
case V4L2_YCBCR_ENC_XV709:
return 1;
case V4L2_YCBCR_ENC_BT2020:
return 9;
case V4L2_YCBCR_ENC_BT2020_CONST_LUM:
return 10;
case V4L2_YCBCR_ENC_SMPTE240M:
default:
return 2;
}
}
ssize_t nal_h264_write_sps(const struct device *dev,
void *dest, size_t n, struct nal_h264_sps *sps);
ssize_t nal_h264_read_sps(const struct device *dev,
struct nal_h264_sps *sps, void *src, size_t n);
void nal_h264_print_sps(const struct device *dev, struct nal_h264_sps *sps);
ssize_t nal_h264_write_pps(const struct device *dev,
void *dest, size_t n, struct nal_h264_pps *pps);
ssize_t nal_h264_read_pps(const struct device *dev,
struct nal_h264_pps *pps, void *src, size_t n);
void nal_h264_print_pps(const struct device *dev, struct nal_h264_pps *pps);
ssize_t nal_h264_write_filler(const struct device *dev, void *dest, size_t n);
ssize_t nal_h264_read_filler(const struct device *dev, void *src, size_t n);
#endif /* __NAL_H264_H__ */
@@ -0,0 +1,884 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2019-2020 Pengutronix, Michael Tretter <kernel@pengutronix.de>
*
* Convert NAL units between raw byte sequence payloads (RBSP) and C structs.
*
* The conversion is defined in "ITU-T Rec. H.265 (02/2018) high efficiency
* video coding". Decoder drivers may use the parser to parse RBSP from
* encoded streams and configure the hardware, if the hardware is not able to
* parse RBSP itself. Encoder drivers may use the generator to generate the
* RBSP for VPS/SPS/PPS nal units and add them to the encoded stream if the
* hardware does not generate the units.
*/
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/string.h>
#include <linux/v4l2-controls.h>
#include <linux/device.h>
#include <linux/export.h>
#include <linux/log2.h>
#include "nal-hevc.h"
#include "nal-rbsp.h"
/*
* See Rec. ITU-T H.265 (02/2018) Table 7-1 - NAL unit type codes and NAL unit
* type classes
*/
enum nal_unit_type {
VPS_NUT = 32,
SPS_NUT = 33,
PPS_NUT = 34,
FD_NUT = 38,
};
static void nal_hevc_write_start_code_prefix(struct rbsp *rbsp)
{
u8 *p = rbsp->data + DIV_ROUND_UP(rbsp->pos, 8);
int i = 4;
if (DIV_ROUND_UP(rbsp->pos, 8) + i > rbsp->size) {
rbsp->error = -EINVAL;
return;
}
p[0] = 0x00;
p[1] = 0x00;
p[2] = 0x00;
p[3] = 0x01;
rbsp->pos += i * 8;
}
static void nal_hevc_read_start_code_prefix(struct rbsp *rbsp)
{
u8 *p = rbsp->data + DIV_ROUND_UP(rbsp->pos, 8);
int i = 4;
if (DIV_ROUND_UP(rbsp->pos, 8) + i > rbsp->size) {
rbsp->error = -EINVAL;
return;
}
if (p[0] != 0x00 || p[1] != 0x00 || p[2] != 0x00 || p[3] != 0x01) {
rbsp->error = -EINVAL;
return;
}
rbsp->pos += i * 8;
}
static void nal_hevc_write_filler_data(struct rbsp *rbsp)
{
u8 *p = rbsp->data + DIV_ROUND_UP(rbsp->pos, 8);
int i;
/* Keep 1 byte extra for terminating the NAL unit */
i = rbsp->size - DIV_ROUND_UP(rbsp->pos, 8) - 1;
memset(p, 0xff, i);
rbsp->pos += i * 8;
}
static void nal_hevc_read_filler_data(struct rbsp *rbsp)
{
u8 *p = rbsp->data + DIV_ROUND_UP(rbsp->pos, 8);
while (*p == 0xff) {
if (DIV_ROUND_UP(rbsp->pos, 8) > rbsp->size) {
rbsp->error = -EINVAL;
return;
}
p++;
rbsp->pos += 8;
}
}
static void nal_hevc_rbsp_profile_tier_level(struct rbsp *rbsp,
struct nal_hevc_profile_tier_level *ptl)
{
unsigned int i;
unsigned int max_num_sub_layers_minus_1 = 0;
rbsp_bits(rbsp, 2, &ptl->general_profile_space);
rbsp_bit(rbsp, &ptl->general_tier_flag);
rbsp_bits(rbsp, 5, &ptl->general_profile_idc);
for (i = 0; i < 32; i++)
rbsp_bit(rbsp, &ptl->general_profile_compatibility_flag[i]);
rbsp_bit(rbsp, &ptl->general_progressive_source_flag);
rbsp_bit(rbsp, &ptl->general_interlaced_source_flag);
rbsp_bit(rbsp, &ptl->general_non_packed_constraint_flag);
rbsp_bit(rbsp, &ptl->general_frame_only_constraint_flag);
if (ptl->general_profile_idc == 4 ||
ptl->general_profile_compatibility_flag[4] ||
ptl->general_profile_idc == 5 ||
ptl->general_profile_compatibility_flag[5] ||
ptl->general_profile_idc == 6 ||
ptl->general_profile_compatibility_flag[6] ||
ptl->general_profile_idc == 7 ||
ptl->general_profile_compatibility_flag[7] ||
ptl->general_profile_idc == 8 ||
ptl->general_profile_compatibility_flag[8] ||
ptl->general_profile_idc == 9 ||
ptl->general_profile_compatibility_flag[9] ||
ptl->general_profile_idc == 10 ||
ptl->general_profile_compatibility_flag[10]) {
rbsp_bit(rbsp, &ptl->general_max_12bit_constraint_flag);
rbsp_bit(rbsp, &ptl->general_max_10bit_constraint_flag);
rbsp_bit(rbsp, &ptl->general_max_8bit_constraint_flag);
rbsp_bit(rbsp, &ptl->general_max_422chroma_constraint_flag);
rbsp_bit(rbsp, &ptl->general_max_420chroma_constraint_flag);
rbsp_bit(rbsp, &ptl->general_max_monochrome_constraint_flag);
rbsp_bit(rbsp, &ptl->general_intra_constraint_flag);
rbsp_bit(rbsp, &ptl->general_one_picture_only_constraint_flag);
rbsp_bit(rbsp, &ptl->general_lower_bit_rate_constraint_flag);
if (ptl->general_profile_idc == 5 ||
ptl->general_profile_compatibility_flag[5] ||
ptl->general_profile_idc == 9 ||
ptl->general_profile_compatibility_flag[9] ||
ptl->general_profile_idc == 10 ||
ptl->general_profile_compatibility_flag[10]) {
rbsp_bit(rbsp, &ptl->general_max_14bit_constraint_flag);
rbsp_bits(rbsp, 32, &ptl->general_reserved_zero_33bits);
rbsp_bits(rbsp, 33 - 32, &ptl->general_reserved_zero_33bits);
} else {
rbsp_bits(rbsp, 32, &ptl->general_reserved_zero_34bits);
rbsp_bits(rbsp, 34 - 2, &ptl->general_reserved_zero_34bits);
}
} else if (ptl->general_profile_idc == 2 ||
ptl->general_profile_compatibility_flag[2]) {
rbsp_bits(rbsp, 7, &ptl->general_reserved_zero_7bits);
rbsp_bit(rbsp, &ptl->general_one_picture_only_constraint_flag);
rbsp_bits(rbsp, 32, &ptl->general_reserved_zero_35bits);
rbsp_bits(rbsp, 35 - 32, &ptl->general_reserved_zero_35bits);
} else {
rbsp_bits(rbsp, 32, &ptl->general_reserved_zero_43bits);
rbsp_bits(rbsp, 43 - 32, &ptl->general_reserved_zero_43bits);
}
if ((ptl->general_profile_idc >= 1 && ptl->general_profile_idc <= 5) ||
ptl->general_profile_idc == 9 ||
ptl->general_profile_compatibility_flag[1] ||
ptl->general_profile_compatibility_flag[2] ||
ptl->general_profile_compatibility_flag[3] ||
ptl->general_profile_compatibility_flag[4] ||
ptl->general_profile_compatibility_flag[5] ||
ptl->general_profile_compatibility_flag[9])
rbsp_bit(rbsp, &ptl->general_inbld_flag);
else
rbsp_bit(rbsp, &ptl->general_reserved_zero_bit);
rbsp_bits(rbsp, 8, &ptl->general_level_idc);
if (max_num_sub_layers_minus_1 > 0)
rbsp_unsupported(rbsp);
}
static void nal_hevc_rbsp_vps(struct rbsp *rbsp, struct nal_hevc_vps *vps)
{
unsigned int i, j;
unsigned int reserved_0xffff_16bits = 0xffff;
rbsp_bits(rbsp, 4, &vps->video_parameter_set_id);
rbsp_bit(rbsp, &vps->base_layer_internal_flag);
rbsp_bit(rbsp, &vps->base_layer_available_flag);
rbsp_bits(rbsp, 6, &vps->max_layers_minus1);
rbsp_bits(rbsp, 3, &vps->max_sub_layers_minus1);
rbsp_bits(rbsp, 1, &vps->temporal_id_nesting_flag);
rbsp_bits(rbsp, 16, &reserved_0xffff_16bits);
nal_hevc_rbsp_profile_tier_level(rbsp, &vps->profile_tier_level);
rbsp_bit(rbsp, &vps->sub_layer_ordering_info_present_flag);
for (i = vps->sub_layer_ordering_info_present_flag ? 0 : vps->max_sub_layers_minus1;
i <= vps->max_sub_layers_minus1; i++) {
rbsp_uev(rbsp, &vps->max_dec_pic_buffering_minus1[i]);
rbsp_uev(rbsp, &vps->max_num_reorder_pics[i]);
rbsp_uev(rbsp, &vps->max_latency_increase_plus1[i]);
}
rbsp_bits(rbsp, 6, &vps->max_layer_id);
rbsp_uev(rbsp, &vps->num_layer_sets_minus1);
for (i = 0; i <= vps->num_layer_sets_minus1; i++)
for (j = 0; j <= vps->max_layer_id; j++)
rbsp_bit(rbsp, &vps->layer_id_included_flag[i][j]);
rbsp_bit(rbsp, &vps->timing_info_present_flag);
if (vps->timing_info_present_flag)
rbsp_unsupported(rbsp);
rbsp_bit(rbsp, &vps->extension_flag);
if (vps->extension_flag)
rbsp_unsupported(rbsp);
}
static void nal_hevc_rbsp_sub_layer_hrd_parameters(struct rbsp *rbsp,
struct nal_hevc_sub_layer_hrd_parameters *hrd)
{
unsigned int i;
unsigned int cpb_cnt = 1;
for (i = 0; i < cpb_cnt; i++) {
rbsp_uev(rbsp, &hrd->bit_rate_value_minus1[i]);
rbsp_uev(rbsp, &hrd->cpb_size_value_minus1[i]);
rbsp_bit(rbsp, &hrd->cbr_flag[i]);
}
}
static void nal_hevc_rbsp_hrd_parameters(struct rbsp *rbsp,
struct nal_hevc_hrd_parameters *hrd)
{
unsigned int i;
unsigned int max_num_sub_layers_minus_1 = 0;
rbsp_bit(rbsp, &hrd->nal_hrd_parameters_present_flag);
rbsp_bit(rbsp, &hrd->vcl_hrd_parameters_present_flag);
if (hrd->nal_hrd_parameters_present_flag || hrd->vcl_hrd_parameters_present_flag) {
rbsp_bit(rbsp, &hrd->sub_pic_hrd_params_present_flag);
if (hrd->sub_pic_hrd_params_present_flag) {
rbsp_bits(rbsp, 8, &hrd->tick_divisor_minus2);
rbsp_bits(rbsp, 5, &hrd->du_cpb_removal_delay_increment_length_minus1);
rbsp_bit(rbsp, &hrd->sub_pic_cpb_params_in_pic_timing_sei_flag);
rbsp_bits(rbsp, 5, &hrd->dpb_output_delay_du_length_minus1);
}
rbsp_bits(rbsp, 4, &hrd->bit_rate_scale);
rbsp_bits(rbsp, 4, &hrd->cpb_size_scale);
if (hrd->sub_pic_hrd_params_present_flag)
rbsp_bits(rbsp, 4, &hrd->cpb_size_du_scale);
rbsp_bits(rbsp, 5, &hrd->initial_cpb_removal_delay_length_minus1);
rbsp_bits(rbsp, 5, &hrd->au_cpb_removal_delay_length_minus1);
rbsp_bits(rbsp, 5, &hrd->dpb_output_delay_length_minus1);
}
for (i = 0; i <= max_num_sub_layers_minus_1; i++) {
rbsp_bit(rbsp, &hrd->fixed_pic_rate_general_flag[i]);
if (!hrd->fixed_pic_rate_general_flag[i])
rbsp_bit(rbsp, &hrd->fixed_pic_rate_within_cvs_flag[i]);
if (hrd->fixed_pic_rate_within_cvs_flag[i])
rbsp_uev(rbsp, &hrd->elemental_duration_in_tc_minus1[i]);
else
rbsp_bit(rbsp, &hrd->low_delay_hrd_flag[i]);
if (!hrd->low_delay_hrd_flag[i])
rbsp_uev(rbsp, &hrd->cpb_cnt_minus1[i]);
if (hrd->nal_hrd_parameters_present_flag)
nal_hevc_rbsp_sub_layer_hrd_parameters(rbsp, &hrd->vcl_hrd[i]);
if (hrd->vcl_hrd_parameters_present_flag)
nal_hevc_rbsp_sub_layer_hrd_parameters(rbsp, &hrd->vcl_hrd[i]);
}
}
static void nal_hevc_rbsp_vui_parameters(struct rbsp *rbsp,
struct nal_hevc_vui_parameters *vui)
{
if (!vui) {
rbsp->error = -EINVAL;
return;
}
rbsp_bit(rbsp, &vui->aspect_ratio_info_present_flag);
if (vui->aspect_ratio_info_present_flag) {
rbsp_bits(rbsp, 8, &vui->aspect_ratio_idc);
if (vui->aspect_ratio_idc == 255) {
rbsp_bits(rbsp, 16, &vui->sar_width);
rbsp_bits(rbsp, 16, &vui->sar_height);
}
}
rbsp_bit(rbsp, &vui->overscan_info_present_flag);
if (vui->overscan_info_present_flag)
rbsp_bit(rbsp, &vui->overscan_appropriate_flag);
rbsp_bit(rbsp, &vui->video_signal_type_present_flag);
if (vui->video_signal_type_present_flag) {
rbsp_bits(rbsp, 3, &vui->video_format);
rbsp_bit(rbsp, &vui->video_full_range_flag);
rbsp_bit(rbsp, &vui->colour_description_present_flag);
if (vui->colour_description_present_flag) {
rbsp_bits(rbsp, 8, &vui->colour_primaries);
rbsp_bits(rbsp, 8, &vui->transfer_characteristics);
rbsp_bits(rbsp, 8, &vui->matrix_coeffs);
}
}
rbsp_bit(rbsp, &vui->chroma_loc_info_present_flag);
if (vui->chroma_loc_info_present_flag) {
rbsp_uev(rbsp, &vui->chroma_sample_loc_type_top_field);
rbsp_uev(rbsp, &vui->chroma_sample_loc_type_bottom_field);
}
rbsp_bit(rbsp, &vui->neutral_chroma_indication_flag);
rbsp_bit(rbsp, &vui->field_seq_flag);
rbsp_bit(rbsp, &vui->frame_field_info_present_flag);
rbsp_bit(rbsp, &vui->default_display_window_flag);
if (vui->default_display_window_flag) {
rbsp_uev(rbsp, &vui->def_disp_win_left_offset);
rbsp_uev(rbsp, &vui->def_disp_win_right_offset);
rbsp_uev(rbsp, &vui->def_disp_win_top_offset);
rbsp_uev(rbsp, &vui->def_disp_win_bottom_offset);
}
rbsp_bit(rbsp, &vui->vui_timing_info_present_flag);
if (vui->vui_timing_info_present_flag) {
rbsp_bits(rbsp, 32, &vui->vui_num_units_in_tick);
rbsp_bits(rbsp, 32, &vui->vui_time_scale);
rbsp_bit(rbsp, &vui->vui_poc_proportional_to_timing_flag);
if (vui->vui_poc_proportional_to_timing_flag)
rbsp_uev(rbsp, &vui->vui_num_ticks_poc_diff_one_minus1);
rbsp_bit(rbsp, &vui->vui_hrd_parameters_present_flag);
if (vui->vui_hrd_parameters_present_flag)
nal_hevc_rbsp_hrd_parameters(rbsp, &vui->nal_hrd_parameters);
}
rbsp_bit(rbsp, &vui->bitstream_restriction_flag);
if (vui->bitstream_restriction_flag) {
rbsp_bit(rbsp, &vui->tiles_fixed_structure_flag);
rbsp_bit(rbsp, &vui->motion_vectors_over_pic_boundaries_flag);
rbsp_bit(rbsp, &vui->restricted_ref_pic_lists_flag);
rbsp_uev(rbsp, &vui->min_spatial_segmentation_idc);
rbsp_uev(rbsp, &vui->max_bytes_per_pic_denom);
rbsp_uev(rbsp, &vui->max_bits_per_min_cu_denom);
rbsp_uev(rbsp, &vui->log2_max_mv_length_horizontal);
rbsp_uev(rbsp, &vui->log2_max_mv_length_vertical);
}
}
static void nal_hevc_rbsp_sps(struct rbsp *rbsp, struct nal_hevc_sps *sps)
{
unsigned int i;
rbsp_bits(rbsp, 4, &sps->video_parameter_set_id);
rbsp_bits(rbsp, 3, &sps->max_sub_layers_minus1);
rbsp_bit(rbsp, &sps->temporal_id_nesting_flag);
nal_hevc_rbsp_profile_tier_level(rbsp, &sps->profile_tier_level);
rbsp_uev(rbsp, &sps->seq_parameter_set_id);
rbsp_uev(rbsp, &sps->chroma_format_idc);
if (sps->chroma_format_idc == 3)
rbsp_bit(rbsp, &sps->separate_colour_plane_flag);
rbsp_uev(rbsp, &sps->pic_width_in_luma_samples);
rbsp_uev(rbsp, &sps->pic_height_in_luma_samples);
rbsp_bit(rbsp, &sps->conformance_window_flag);
if (sps->conformance_window_flag) {
rbsp_uev(rbsp, &sps->conf_win_left_offset);
rbsp_uev(rbsp, &sps->conf_win_right_offset);
rbsp_uev(rbsp, &sps->conf_win_top_offset);
rbsp_uev(rbsp, &sps->conf_win_bottom_offset);
}
rbsp_uev(rbsp, &sps->bit_depth_luma_minus8);
rbsp_uev(rbsp, &sps->bit_depth_chroma_minus8);
rbsp_uev(rbsp, &sps->log2_max_pic_order_cnt_lsb_minus4);
rbsp_bit(rbsp, &sps->sub_layer_ordering_info_present_flag);
for (i = (sps->sub_layer_ordering_info_present_flag ? 0 : sps->max_sub_layers_minus1);
i <= sps->max_sub_layers_minus1; i++) {
rbsp_uev(rbsp, &sps->max_dec_pic_buffering_minus1[i]);
rbsp_uev(rbsp, &sps->max_num_reorder_pics[i]);
rbsp_uev(rbsp, &sps->max_latency_increase_plus1[i]);
}
rbsp_uev(rbsp, &sps->log2_min_luma_coding_block_size_minus3);
rbsp_uev(rbsp, &sps->log2_diff_max_min_luma_coding_block_size);
rbsp_uev(rbsp, &sps->log2_min_luma_transform_block_size_minus2);
rbsp_uev(rbsp, &sps->log2_diff_max_min_luma_transform_block_size);
rbsp_uev(rbsp, &sps->max_transform_hierarchy_depth_inter);
rbsp_uev(rbsp, &sps->max_transform_hierarchy_depth_intra);
rbsp_bit(rbsp, &sps->scaling_list_enabled_flag);
if (sps->scaling_list_enabled_flag)
rbsp_unsupported(rbsp);
rbsp_bit(rbsp, &sps->amp_enabled_flag);
rbsp_bit(rbsp, &sps->sample_adaptive_offset_enabled_flag);
rbsp_bit(rbsp, &sps->pcm_enabled_flag);
if (sps->pcm_enabled_flag) {
rbsp_bits(rbsp, 4, &sps->pcm_sample_bit_depth_luma_minus1);
rbsp_bits(rbsp, 4, &sps->pcm_sample_bit_depth_chroma_minus1);
rbsp_uev(rbsp, &sps->log2_min_pcm_luma_coding_block_size_minus3);
rbsp_uev(rbsp, &sps->log2_diff_max_min_pcm_luma_coding_block_size);
rbsp_bit(rbsp, &sps->pcm_loop_filter_disabled_flag);
}
rbsp_uev(rbsp, &sps->num_short_term_ref_pic_sets);
if (sps->num_short_term_ref_pic_sets > 0)
rbsp_unsupported(rbsp);
rbsp_bit(rbsp, &sps->long_term_ref_pics_present_flag);
if (sps->long_term_ref_pics_present_flag)
rbsp_unsupported(rbsp);
rbsp_bit(rbsp, &sps->sps_temporal_mvp_enabled_flag);
rbsp_bit(rbsp, &sps->strong_intra_smoothing_enabled_flag);
rbsp_bit(rbsp, &sps->vui_parameters_present_flag);
if (sps->vui_parameters_present_flag)
nal_hevc_rbsp_vui_parameters(rbsp, &sps->vui);
rbsp_bit(rbsp, &sps->extension_present_flag);
if (sps->extension_present_flag) {
rbsp_bit(rbsp, &sps->sps_range_extension_flag);
rbsp_bit(rbsp, &sps->sps_multilayer_extension_flag);
rbsp_bit(rbsp, &sps->sps_3d_extension_flag);
rbsp_bit(rbsp, &sps->sps_scc_extension_flag);
rbsp_bits(rbsp, 5, &sps->sps_extension_4bits);
}
if (sps->sps_range_extension_flag)
rbsp_unsupported(rbsp);
if (sps->sps_multilayer_extension_flag)
rbsp_unsupported(rbsp);
if (sps->sps_3d_extension_flag)
rbsp_unsupported(rbsp);
if (sps->sps_scc_extension_flag)
rbsp_unsupported(rbsp);
if (sps->sps_extension_4bits)
rbsp_unsupported(rbsp);
}
static void nal_hevc_rbsp_pps(struct rbsp *rbsp, struct nal_hevc_pps *pps)
{
unsigned int i;
rbsp_uev(rbsp, &pps->pps_pic_parameter_set_id);
rbsp_uev(rbsp, &pps->pps_seq_parameter_set_id);
rbsp_bit(rbsp, &pps->dependent_slice_segments_enabled_flag);
rbsp_bit(rbsp, &pps->output_flag_present_flag);
rbsp_bits(rbsp, 3, &pps->num_extra_slice_header_bits);
rbsp_bit(rbsp, &pps->sign_data_hiding_enabled_flag);
rbsp_bit(rbsp, &pps->cabac_init_present_flag);
rbsp_uev(rbsp, &pps->num_ref_idx_l0_default_active_minus1);
rbsp_uev(rbsp, &pps->num_ref_idx_l1_default_active_minus1);
rbsp_sev(rbsp, &pps->init_qp_minus26);
rbsp_bit(rbsp, &pps->constrained_intra_pred_flag);
rbsp_bit(rbsp, &pps->transform_skip_enabled_flag);
rbsp_bit(rbsp, &pps->cu_qp_delta_enabled_flag);
if (pps->cu_qp_delta_enabled_flag)
rbsp_uev(rbsp, &pps->diff_cu_qp_delta_depth);
rbsp_sev(rbsp, &pps->pps_cb_qp_offset);
rbsp_sev(rbsp, &pps->pps_cr_qp_offset);
rbsp_bit(rbsp, &pps->pps_slice_chroma_qp_offsets_present_flag);
rbsp_bit(rbsp, &pps->weighted_pred_flag);
rbsp_bit(rbsp, &pps->weighted_bipred_flag);
rbsp_bit(rbsp, &pps->transquant_bypass_enabled_flag);
rbsp_bit(rbsp, &pps->tiles_enabled_flag);
rbsp_bit(rbsp, &pps->entropy_coding_sync_enabled_flag);
if (pps->tiles_enabled_flag) {
rbsp_uev(rbsp, &pps->num_tile_columns_minus1);
rbsp_uev(rbsp, &pps->num_tile_rows_minus1);
rbsp_bit(rbsp, &pps->uniform_spacing_flag);
if (!pps->uniform_spacing_flag) {
for (i = 0; i < pps->num_tile_columns_minus1; i++)
rbsp_uev(rbsp, &pps->column_width_minus1[i]);
for (i = 0; i < pps->num_tile_rows_minus1; i++)
rbsp_uev(rbsp, &pps->row_height_minus1[i]);
}
rbsp_bit(rbsp, &pps->loop_filter_across_tiles_enabled_flag);
}
rbsp_bit(rbsp, &pps->pps_loop_filter_across_slices_enabled_flag);
rbsp_bit(rbsp, &pps->deblocking_filter_control_present_flag);
if (pps->deblocking_filter_control_present_flag) {
rbsp_bit(rbsp, &pps->deblocking_filter_override_enabled_flag);
rbsp_bit(rbsp, &pps->pps_deblocking_filter_disabled_flag);
if (!pps->pps_deblocking_filter_disabled_flag) {
rbsp_sev(rbsp, &pps->pps_beta_offset_div2);
rbsp_sev(rbsp, &pps->pps_tc_offset_div2);
}
}
rbsp_bit(rbsp, &pps->pps_scaling_list_data_present_flag);
if (pps->pps_scaling_list_data_present_flag)
rbsp_unsupported(rbsp);
rbsp_bit(rbsp, &pps->lists_modification_present_flag);
rbsp_uev(rbsp, &pps->log2_parallel_merge_level_minus2);
rbsp_bit(rbsp, &pps->slice_segment_header_extension_present_flag);
rbsp_bit(rbsp, &pps->pps_extension_present_flag);
if (pps->pps_extension_present_flag) {
rbsp_bit(rbsp, &pps->pps_range_extension_flag);
rbsp_bit(rbsp, &pps->pps_multilayer_extension_flag);
rbsp_bit(rbsp, &pps->pps_3d_extension_flag);
rbsp_bit(rbsp, &pps->pps_scc_extension_flag);
rbsp_bits(rbsp, 4, &pps->pps_extension_4bits);
}
if (pps->pps_range_extension_flag)
rbsp_unsupported(rbsp);
if (pps->pps_multilayer_extension_flag)
rbsp_unsupported(rbsp);
if (pps->pps_3d_extension_flag)
rbsp_unsupported(rbsp);
if (pps->pps_scc_extension_flag)
rbsp_unsupported(rbsp);
if (pps->pps_extension_4bits)
rbsp_unsupported(rbsp);
}
/**
* nal_hevc_write_vps() - Write PPS NAL unit into RBSP format
* @dev: device pointer
* @dest: the buffer that is filled with RBSP data
* @n: maximum size of @dest in bytes
* @vps: &struct nal_hevc_vps to convert to RBSP
*
* Convert @vps to RBSP data and write it into @dest.
*
* The size of the VPS NAL unit is not known in advance and this function will
* fail, if @dest does not hold sufficient space for the VPS NAL unit.
*
* Return: number of bytes written to @dest or negative error code
*/
ssize_t nal_hevc_write_vps(const struct device *dev,
void *dest, size_t n, struct nal_hevc_vps *vps)
{
struct rbsp rbsp;
unsigned int forbidden_zero_bit = 0;
unsigned int nal_unit_type = VPS_NUT;
unsigned int nuh_layer_id = 0;
unsigned int nuh_temporal_id_plus1 = 1;
if (!dest)
return -EINVAL;
rbsp_init(&rbsp, dest, n, &write);
nal_hevc_write_start_code_prefix(&rbsp);
/* NAL unit header */
rbsp_bit(&rbsp, &forbidden_zero_bit);
rbsp_bits(&rbsp, 6, &nal_unit_type);
rbsp_bits(&rbsp, 6, &nuh_layer_id);
rbsp_bits(&rbsp, 3, &nuh_temporal_id_plus1);
nal_hevc_rbsp_vps(&rbsp, vps);
rbsp_trailing_bits(&rbsp);
if (rbsp.error)
return rbsp.error;
return DIV_ROUND_UP(rbsp.pos, 8);
}
EXPORT_SYMBOL_GPL(nal_hevc_write_vps);
/**
* nal_hevc_read_vps() - Read VPS NAL unit from RBSP format
* @dev: device pointer
* @vps: the &struct nal_hevc_vps to fill from the RBSP data
* @src: the buffer that contains the RBSP data
* @n: size of @src in bytes
*
* Read RBSP data from @src and use it to fill @vps.
*
* Return: number of bytes read from @src or negative error code
*/
ssize_t nal_hevc_read_vps(const struct device *dev,
struct nal_hevc_vps *vps, void *src, size_t n)
{
struct rbsp rbsp;
unsigned int forbidden_zero_bit;
unsigned int nal_unit_type;
unsigned int nuh_layer_id;
unsigned int nuh_temporal_id_plus1;
if (!src)
return -EINVAL;
rbsp_init(&rbsp, src, n, &read);
nal_hevc_read_start_code_prefix(&rbsp);
rbsp_bit(&rbsp, &forbidden_zero_bit);
rbsp_bits(&rbsp, 6, &nal_unit_type);
rbsp_bits(&rbsp, 6, &nuh_layer_id);
rbsp_bits(&rbsp, 3, &nuh_temporal_id_plus1);
if (rbsp.error ||
forbidden_zero_bit != 0 ||
nal_unit_type != VPS_NUT)
return -EINVAL;
nal_hevc_rbsp_vps(&rbsp, vps);
rbsp_trailing_bits(&rbsp);
if (rbsp.error)
return rbsp.error;
return DIV_ROUND_UP(rbsp.pos, 8);
}
EXPORT_SYMBOL_GPL(nal_hevc_read_vps);
/**
* nal_hevc_write_sps() - Write SPS NAL unit into RBSP format
* @dev: device pointer
* @dest: the buffer that is filled with RBSP data
* @n: maximum size of @dest in bytes
* @sps: &struct nal_hevc_sps to convert to RBSP
*
* Convert @sps to RBSP data and write it into @dest.
*
* The size of the SPS NAL unit is not known in advance and this function will
* fail, if @dest does not hold sufficient space for the SPS NAL unit.
*
* Return: number of bytes written to @dest or negative error code
*/
ssize_t nal_hevc_write_sps(const struct device *dev,
void *dest, size_t n, struct nal_hevc_sps *sps)
{
struct rbsp rbsp;
unsigned int forbidden_zero_bit = 0;
unsigned int nal_unit_type = SPS_NUT;
unsigned int nuh_layer_id = 0;
unsigned int nuh_temporal_id_plus1 = 1;
if (!dest)
return -EINVAL;
rbsp_init(&rbsp, dest, n, &write);
nal_hevc_write_start_code_prefix(&rbsp);
/* NAL unit header */
rbsp_bit(&rbsp, &forbidden_zero_bit);
rbsp_bits(&rbsp, 6, &nal_unit_type);
rbsp_bits(&rbsp, 6, &nuh_layer_id);
rbsp_bits(&rbsp, 3, &nuh_temporal_id_plus1);
nal_hevc_rbsp_sps(&rbsp, sps);
rbsp_trailing_bits(&rbsp);
if (rbsp.error)
return rbsp.error;
return DIV_ROUND_UP(rbsp.pos, 8);
}
EXPORT_SYMBOL_GPL(nal_hevc_write_sps);
/**
* nal_hevc_read_sps() - Read SPS NAL unit from RBSP format
* @dev: device pointer
* @sps: the &struct nal_hevc_sps to fill from the RBSP data
* @src: the buffer that contains the RBSP data
* @n: size of @src in bytes
*
* Read RBSP data from @src and use it to fill @sps.
*
* Return: number of bytes read from @src or negative error code
*/
ssize_t nal_hevc_read_sps(const struct device *dev,
struct nal_hevc_sps *sps, void *src, size_t n)
{
struct rbsp rbsp;
unsigned int forbidden_zero_bit;
unsigned int nal_unit_type;
unsigned int nuh_layer_id;
unsigned int nuh_temporal_id_plus1;
if (!src)
return -EINVAL;
rbsp_init(&rbsp, src, n, &read);
nal_hevc_read_start_code_prefix(&rbsp);
rbsp_bit(&rbsp, &forbidden_zero_bit);
rbsp_bits(&rbsp, 6, &nal_unit_type);
rbsp_bits(&rbsp, 6, &nuh_layer_id);
rbsp_bits(&rbsp, 3, &nuh_temporal_id_plus1);
if (rbsp.error ||
forbidden_zero_bit != 0 ||
nal_unit_type != SPS_NUT)
return -EINVAL;
nal_hevc_rbsp_sps(&rbsp, sps);
rbsp_trailing_bits(&rbsp);
if (rbsp.error)
return rbsp.error;
return DIV_ROUND_UP(rbsp.pos, 8);
}
EXPORT_SYMBOL_GPL(nal_hevc_read_sps);
/**
* nal_hevc_write_pps() - Write PPS NAL unit into RBSP format
* @dev: device pointer
* @dest: the buffer that is filled with RBSP data
* @n: maximum size of @dest in bytes
* @pps: &struct nal_hevc_pps to convert to RBSP
*
* Convert @pps to RBSP data and write it into @dest.
*
* The size of the PPS NAL unit is not known in advance and this function will
* fail, if @dest does not hold sufficient space for the PPS NAL unit.
*
* Return: number of bytes written to @dest or negative error code
*/
ssize_t nal_hevc_write_pps(const struct device *dev,
void *dest, size_t n, struct nal_hevc_pps *pps)
{
struct rbsp rbsp;
unsigned int forbidden_zero_bit = 0;
unsigned int nal_unit_type = PPS_NUT;
unsigned int nuh_layer_id = 0;
unsigned int nuh_temporal_id_plus1 = 1;
if (!dest)
return -EINVAL;
rbsp_init(&rbsp, dest, n, &write);
nal_hevc_write_start_code_prefix(&rbsp);
/* NAL unit header */
rbsp_bit(&rbsp, &forbidden_zero_bit);
rbsp_bits(&rbsp, 6, &nal_unit_type);
rbsp_bits(&rbsp, 6, &nuh_layer_id);
rbsp_bits(&rbsp, 3, &nuh_temporal_id_plus1);
nal_hevc_rbsp_pps(&rbsp, pps);
rbsp_trailing_bits(&rbsp);
if (rbsp.error)
return rbsp.error;
return DIV_ROUND_UP(rbsp.pos, 8);
}
EXPORT_SYMBOL_GPL(nal_hevc_write_pps);
/**
* nal_hevc_read_pps() - Read PPS NAL unit from RBSP format
* @dev: device pointer
* @pps: the &struct nal_hevc_pps to fill from the RBSP data
* @src: the buffer that contains the RBSP data
* @n: size of @src in bytes
*
* Read RBSP data from @src and use it to fill @pps.
*
* Return: number of bytes read from @src or negative error code
*/
ssize_t nal_hevc_read_pps(const struct device *dev,
struct nal_hevc_pps *pps, void *src, size_t n)
{
struct rbsp rbsp;
unsigned int forbidden_zero_bit;
unsigned int nal_unit_type;
unsigned int nuh_layer_id;
unsigned int nuh_temporal_id_plus1;
if (!src)
return -EINVAL;
rbsp_init(&rbsp, src, n, &read);
nal_hevc_read_start_code_prefix(&rbsp);
/* NAL unit header */
rbsp_bit(&rbsp, &forbidden_zero_bit);
rbsp_bits(&rbsp, 6, &nal_unit_type);
rbsp_bits(&rbsp, 6, &nuh_layer_id);
rbsp_bits(&rbsp, 3, &nuh_temporal_id_plus1);
nal_hevc_rbsp_pps(&rbsp, pps);
rbsp_trailing_bits(&rbsp);
if (rbsp.error)
return rbsp.error;
return DIV_ROUND_UP(rbsp.pos, 8);
}
EXPORT_SYMBOL_GPL(nal_hevc_read_pps);
/**
* nal_hevc_write_filler() - Write filler data RBSP
* @dev: device pointer
* @dest: buffer to fill with filler data
* @n: size of the buffer to fill with filler data
*
* Write a filler data RBSP to @dest with a size of @n bytes and return the
* number of written filler data bytes.
*
* Use this function to generate dummy data in an RBSP data stream that can be
* safely ignored by hevc decoders.
*
* The RBSP format of the filler data is specified in Rec. ITU-T H.265
* (02/2018) 7.3.2.8 Filler data RBSP syntax.
*
* Return: number of filler data bytes (including marker) or negative error
*/
ssize_t nal_hevc_write_filler(const struct device *dev, void *dest, size_t n)
{
struct rbsp rbsp;
unsigned int forbidden_zero_bit = 0;
unsigned int nal_unit_type = FD_NUT;
unsigned int nuh_layer_id = 0;
unsigned int nuh_temporal_id_plus1 = 1;
if (!dest)
return -EINVAL;
rbsp_init(&rbsp, dest, n, &write);
nal_hevc_write_start_code_prefix(&rbsp);
rbsp_bit(&rbsp, &forbidden_zero_bit);
rbsp_bits(&rbsp, 6, &nal_unit_type);
rbsp_bits(&rbsp, 6, &nuh_layer_id);
rbsp_bits(&rbsp, 3, &nuh_temporal_id_plus1);
nal_hevc_write_filler_data(&rbsp);
rbsp_trailing_bits(&rbsp);
if (rbsp.error)
return rbsp.error;
return DIV_ROUND_UP(rbsp.pos, 8);
}
EXPORT_SYMBOL_GPL(nal_hevc_write_filler);
/**
* nal_hevc_read_filler() - Read filler data RBSP
* @dev: device pointer
* @src: buffer with RBSP data that is read
* @n: maximum size of src that shall be read
*
* Read a filler data RBSP from @src up to a maximum size of @n bytes and
* return the size of the filler data in bytes including the marker.
*
* This function is used to parse filler data and skip the respective bytes in
* the RBSP data.
*
* The RBSP format of the filler data is specified in Rec. ITU-T H.265
* (02/2018) 7.3.2.8 Filler data RBSP syntax.
*
* Return: number of filler data bytes (including marker) or negative error
*/
ssize_t nal_hevc_read_filler(const struct device *dev, void *src, size_t n)
{
struct rbsp rbsp;
unsigned int forbidden_zero_bit;
unsigned int nal_unit_type;
unsigned int nuh_layer_id;
unsigned int nuh_temporal_id_plus1;
if (!src)
return -EINVAL;
rbsp_init(&rbsp, src, n, &read);
nal_hevc_read_start_code_prefix(&rbsp);
rbsp_bit(&rbsp, &forbidden_zero_bit);
rbsp_bits(&rbsp, 6, &nal_unit_type);
rbsp_bits(&rbsp, 6, &nuh_layer_id);
rbsp_bits(&rbsp, 3, &nuh_temporal_id_plus1);
if (rbsp.error)
return rbsp.error;
if (forbidden_zero_bit != 0 ||
nal_unit_type != FD_NUT)
return -EINVAL;
nal_hevc_read_filler_data(&rbsp);
rbsp_trailing_bits(&rbsp);
if (rbsp.error)
return rbsp.error;
return DIV_ROUND_UP(rbsp.pos, 8);
}
EXPORT_SYMBOL_GPL(nal_hevc_read_filler);
@@ -0,0 +1,520 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) 2019 Pengutronix, Michael Tretter <kernel@pengutronix.de>
*
* Convert NAL units between raw byte sequence payloads (RBSP) and C structs.
*/
#ifndef __NAL_HEVC_H__
#define __NAL_HEVC_H__
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/v4l2-controls.h>
#include <linux/videodev2.h>
struct nal_hevc_profile_tier_level {
unsigned int general_profile_space;
unsigned int general_tier_flag;
unsigned int general_profile_idc;
unsigned int general_profile_compatibility_flag[32];
unsigned int general_progressive_source_flag;
unsigned int general_interlaced_source_flag;
unsigned int general_non_packed_constraint_flag;
unsigned int general_frame_only_constraint_flag;
union {
struct {
unsigned int general_max_12bit_constraint_flag;
unsigned int general_max_10bit_constraint_flag;
unsigned int general_max_8bit_constraint_flag;
unsigned int general_max_422chroma_constraint_flag;
unsigned int general_max_420chroma_constraint_flag;
unsigned int general_max_monochrome_constraint_flag;
unsigned int general_intra_constraint_flag;
unsigned int general_one_picture_only_constraint_flag;
unsigned int general_lower_bit_rate_constraint_flag;
union {
struct {
unsigned int general_max_14bit_constraint_flag;
unsigned int general_reserved_zero_33bits;
};
unsigned int general_reserved_zero_34bits;
};
};
struct {
unsigned int general_reserved_zero_7bits;
/* unsigned int general_one_picture_only_constraint_flag; */
unsigned int general_reserved_zero_35bits;
};
unsigned int general_reserved_zero_43bits;
};
union {
unsigned int general_inbld_flag;
unsigned int general_reserved_zero_bit;
};
unsigned int general_level_idc;
};
/*
* struct nal_hevc_vps - Video parameter set
*
* C struct representation of the video parameter set NAL unit as defined by
* Rec. ITU-T H.265 (02/2018) 7.3.2.1 Video parameter set RBSP syntax
*/
struct nal_hevc_vps {
unsigned int video_parameter_set_id;
unsigned int base_layer_internal_flag;
unsigned int base_layer_available_flag;
unsigned int max_layers_minus1;
unsigned int max_sub_layers_minus1;
unsigned int temporal_id_nesting_flag;
struct nal_hevc_profile_tier_level profile_tier_level;
unsigned int sub_layer_ordering_info_present_flag;
struct {
unsigned int max_dec_pic_buffering_minus1[7];
unsigned int max_num_reorder_pics[7];
unsigned int max_latency_increase_plus1[7];
};
unsigned int max_layer_id;
unsigned int num_layer_sets_minus1;
unsigned int layer_id_included_flag[1024][64];
unsigned int timing_info_present_flag;
struct {
unsigned int num_units_in_tick;
unsigned int time_scale;
unsigned int poc_proportional_to_timing_flag;
unsigned int num_ticks_poc_diff_one_minus1;
unsigned int num_hrd_parameters;
struct {
unsigned int hrd_layer_set_idx[0];
unsigned int cprms_present_flag[0];
};
/* hrd_parameters( cprms_present_flag[ i ], max_sub_layers_minus1 ) */
};
unsigned int extension_flag;
unsigned int extension_data_flag;
};
#define N_HRD_PARAMS 1
struct nal_hevc_sub_layer_hrd_parameters {
unsigned int bit_rate_value_minus1[N_HRD_PARAMS];
unsigned int cpb_size_value_minus1[N_HRD_PARAMS];
unsigned int cbr_flag[N_HRD_PARAMS];
};
struct nal_hevc_hrd_parameters {
unsigned int nal_hrd_parameters_present_flag;
unsigned int vcl_hrd_parameters_present_flag;
struct {
unsigned int sub_pic_hrd_params_present_flag;
struct {
unsigned int tick_divisor_minus2;
unsigned int du_cpb_removal_delay_increment_length_minus1;
unsigned int sub_pic_cpb_params_in_pic_timing_sei_flag;
unsigned int dpb_output_delay_du_length_minus1;
};
unsigned int bit_rate_scale;
unsigned int cpb_size_scale;
unsigned int cpb_size_du_scale;
unsigned int initial_cpb_removal_delay_length_minus1;
unsigned int au_cpb_removal_delay_length_minus1;
unsigned int dpb_output_delay_length_minus1;
};
struct {
unsigned int fixed_pic_rate_general_flag[1];
unsigned int fixed_pic_rate_within_cvs_flag[1];
unsigned int elemental_duration_in_tc_minus1[1];
unsigned int low_delay_hrd_flag[1];
unsigned int cpb_cnt_minus1[1];
struct nal_hevc_sub_layer_hrd_parameters nal_hrd[1];
struct nal_hevc_sub_layer_hrd_parameters vcl_hrd[1];
};
};
/*
* struct nal_hevc_vui_parameters - VUI parameters
*
* C struct representation of the VUI parameters as defined by Rec. ITU-T
* H.265 (02/2018) E.2.1 VUI parameters syntax.
*/
struct nal_hevc_vui_parameters {
unsigned int aspect_ratio_info_present_flag;
struct {
unsigned int aspect_ratio_idc;
unsigned int sar_width;
unsigned int sar_height;
};
unsigned int overscan_info_present_flag;
unsigned int overscan_appropriate_flag;
unsigned int video_signal_type_present_flag;
struct {
unsigned int video_format;
unsigned int video_full_range_flag;
unsigned int colour_description_present_flag;
struct {
unsigned int colour_primaries;
unsigned int transfer_characteristics;
unsigned int matrix_coeffs;
};
};
unsigned int chroma_loc_info_present_flag;
struct {
unsigned int chroma_sample_loc_type_top_field;
unsigned int chroma_sample_loc_type_bottom_field;
};
unsigned int neutral_chroma_indication_flag;
unsigned int field_seq_flag;
unsigned int frame_field_info_present_flag;
unsigned int default_display_window_flag;
struct {
unsigned int def_disp_win_left_offset;
unsigned int def_disp_win_right_offset;
unsigned int def_disp_win_top_offset;
unsigned int def_disp_win_bottom_offset;
};
unsigned int vui_timing_info_present_flag;
struct {
unsigned int vui_num_units_in_tick;
unsigned int vui_time_scale;
unsigned int vui_poc_proportional_to_timing_flag;
unsigned int vui_num_ticks_poc_diff_one_minus1;
unsigned int vui_hrd_parameters_present_flag;
struct nal_hevc_hrd_parameters nal_hrd_parameters;
};
unsigned int bitstream_restriction_flag;
struct {
unsigned int tiles_fixed_structure_flag;
unsigned int motion_vectors_over_pic_boundaries_flag;
unsigned int restricted_ref_pic_lists_flag;
unsigned int min_spatial_segmentation_idc;
unsigned int max_bytes_per_pic_denom;
unsigned int max_bits_per_min_cu_denom;
unsigned int log2_max_mv_length_horizontal;
unsigned int log2_max_mv_length_vertical;
};
};
/*
* struct nal_hevc_sps - Sequence parameter set
*
* C struct representation of the video parameter set NAL unit as defined by
* Rec. ITU-T H.265 (02/2018) 7.3.2.2 Sequence parameter set RBSP syntax
*/
struct nal_hevc_sps {
unsigned int video_parameter_set_id;
unsigned int max_sub_layers_minus1;
unsigned int temporal_id_nesting_flag;
struct nal_hevc_profile_tier_level profile_tier_level;
unsigned int seq_parameter_set_id;
unsigned int chroma_format_idc;
unsigned int separate_colour_plane_flag;
unsigned int pic_width_in_luma_samples;
unsigned int pic_height_in_luma_samples;
unsigned int conformance_window_flag;
struct {
unsigned int conf_win_left_offset;
unsigned int conf_win_right_offset;
unsigned int conf_win_top_offset;
unsigned int conf_win_bottom_offset;
};
unsigned int bit_depth_luma_minus8;
unsigned int bit_depth_chroma_minus8;
unsigned int log2_max_pic_order_cnt_lsb_minus4;
unsigned int sub_layer_ordering_info_present_flag;
struct {
unsigned int max_dec_pic_buffering_minus1[7];
unsigned int max_num_reorder_pics[7];
unsigned int max_latency_increase_plus1[7];
};
unsigned int log2_min_luma_coding_block_size_minus3;
unsigned int log2_diff_max_min_luma_coding_block_size;
unsigned int log2_min_luma_transform_block_size_minus2;
unsigned int log2_diff_max_min_luma_transform_block_size;
unsigned int max_transform_hierarchy_depth_inter;
unsigned int max_transform_hierarchy_depth_intra;
unsigned int scaling_list_enabled_flag;
unsigned int scaling_list_data_present_flag;
unsigned int amp_enabled_flag;
unsigned int sample_adaptive_offset_enabled_flag;
unsigned int pcm_enabled_flag;
struct {
unsigned int pcm_sample_bit_depth_luma_minus1;
unsigned int pcm_sample_bit_depth_chroma_minus1;
unsigned int log2_min_pcm_luma_coding_block_size_minus3;
unsigned int log2_diff_max_min_pcm_luma_coding_block_size;
unsigned int pcm_loop_filter_disabled_flag;
};
unsigned int num_short_term_ref_pic_sets;
unsigned int long_term_ref_pics_present_flag;
unsigned int sps_temporal_mvp_enabled_flag;
unsigned int strong_intra_smoothing_enabled_flag;
unsigned int vui_parameters_present_flag;
struct nal_hevc_vui_parameters vui;
unsigned int extension_present_flag;
struct {
unsigned int sps_range_extension_flag;
unsigned int sps_multilayer_extension_flag;
unsigned int sps_3d_extension_flag;
unsigned int sps_scc_extension_flag;
unsigned int sps_extension_4bits;
};
};
struct nal_hevc_pps {
unsigned int pps_pic_parameter_set_id;
unsigned int pps_seq_parameter_set_id;
unsigned int dependent_slice_segments_enabled_flag;
unsigned int output_flag_present_flag;
unsigned int num_extra_slice_header_bits;
unsigned int sign_data_hiding_enabled_flag;
unsigned int cabac_init_present_flag;
unsigned int num_ref_idx_l0_default_active_minus1;
unsigned int num_ref_idx_l1_default_active_minus1;
int init_qp_minus26;
unsigned int constrained_intra_pred_flag;
unsigned int transform_skip_enabled_flag;
unsigned int cu_qp_delta_enabled_flag;
unsigned int diff_cu_qp_delta_depth;
int pps_cb_qp_offset;
int pps_cr_qp_offset;
unsigned int pps_slice_chroma_qp_offsets_present_flag;
unsigned int weighted_pred_flag;
unsigned int weighted_bipred_flag;
unsigned int transquant_bypass_enabled_flag;
unsigned int tiles_enabled_flag;
unsigned int entropy_coding_sync_enabled_flag;
struct {
unsigned int num_tile_columns_minus1;
unsigned int num_tile_rows_minus1;
unsigned int uniform_spacing_flag;
struct {
unsigned int column_width_minus1[1];
unsigned int row_height_minus1[1];
};
unsigned int loop_filter_across_tiles_enabled_flag;
};
unsigned int pps_loop_filter_across_slices_enabled_flag;
unsigned int deblocking_filter_control_present_flag;
struct {
unsigned int deblocking_filter_override_enabled_flag;
unsigned int pps_deblocking_filter_disabled_flag;
struct {
int pps_beta_offset_div2;
int pps_tc_offset_div2;
};
};
unsigned int pps_scaling_list_data_present_flag;
unsigned int lists_modification_present_flag;
unsigned int log2_parallel_merge_level_minus2;
unsigned int slice_segment_header_extension_present_flag;
unsigned int pps_extension_present_flag;
struct {
unsigned int pps_range_extension_flag;
unsigned int pps_multilayer_extension_flag;
unsigned int pps_3d_extension_flag;
unsigned int pps_scc_extension_flag;
unsigned int pps_extension_4bits;
};
};
/**
* nal_hevc_profile() - Get profile_idc for v4l2 hevc profile
* @profile: the profile as &enum v4l2_mpeg_video_hevc_profile
*
* Convert the &enum v4l2_mpeg_video_hevc_profile to profile_idc as specified
* in Rec. ITU-T H.265 (02/2018) A.3.
*
* Return: the profile_idc for the passed level
*/
static inline int nal_hevc_profile(enum v4l2_mpeg_video_hevc_profile profile)
{
switch (profile) {
case V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN:
return 1;
case V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10:
return 2;
case V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE:
return 3;
default:
return -EINVAL;
}
}
/**
* nal_hevc_tier() - Get tier_flag for v4l2 hevc tier
* @tier: the tier as &enum v4l2_mpeg_video_hevc_tier
*
* Convert the &enum v4l2_mpeg_video_hevc_tier to tier_flag as specified
* in Rec. ITU-T H.265 (02/2018) A.4.1.
*
* Return: the tier_flag for the passed tier
*/
static inline int nal_hevc_tier(enum v4l2_mpeg_video_hevc_tier tier)
{
switch (tier) {
case V4L2_MPEG_VIDEO_HEVC_TIER_MAIN:
return 0;
case V4L2_MPEG_VIDEO_HEVC_TIER_HIGH:
return 1;
default:
return -EINVAL;
}
}
/**
* nal_hevc_level() - Get level_idc for v4l2 hevc level
* @level: the level as &enum v4l2_mpeg_video_hevc_level
*
* Convert the &enum v4l2_mpeg_video_hevc_level to level_idc as specified in
* Rec. ITU-T H.265 (02/2018) A.4.1.
*
* Return: the level_idc for the passed level
*/
static inline int nal_hevc_level(enum v4l2_mpeg_video_hevc_level level)
{
/*
* T-Rec-H.265 p. 280: general_level_idc and sub_layer_level_idc[ i ]
* shall be set equal to a value of 30 times the level number
* specified in Table A.6.
*/
int factor = 30 / 10;
switch (level) {
case V4L2_MPEG_VIDEO_HEVC_LEVEL_1:
return factor * 10;
case V4L2_MPEG_VIDEO_HEVC_LEVEL_2:
return factor * 20;
case V4L2_MPEG_VIDEO_HEVC_LEVEL_2_1:
return factor * 21;
case V4L2_MPEG_VIDEO_HEVC_LEVEL_3:
return factor * 30;
case V4L2_MPEG_VIDEO_HEVC_LEVEL_3_1:
return factor * 31;
case V4L2_MPEG_VIDEO_HEVC_LEVEL_4:
return factor * 40;
case V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1:
return factor * 41;
case V4L2_MPEG_VIDEO_HEVC_LEVEL_5:
return factor * 50;
case V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1:
return factor * 51;
case V4L2_MPEG_VIDEO_HEVC_LEVEL_5_2:
return factor * 52;
case V4L2_MPEG_VIDEO_HEVC_LEVEL_6:
return factor * 60;
case V4L2_MPEG_VIDEO_HEVC_LEVEL_6_1:
return factor * 61;
case V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2:
return factor * 62;
default:
return -EINVAL;
}
}
static inline int nal_hevc_full_range(enum v4l2_quantization quantization)
{
switch (quantization) {
case V4L2_QUANTIZATION_FULL_RANGE:
return 1;
case V4L2_QUANTIZATION_LIM_RANGE:
return 0;
default:
break;
}
return 0;
}
static inline int nal_hevc_color_primaries(enum v4l2_colorspace colorspace)
{
switch (colorspace) {
case V4L2_COLORSPACE_SMPTE170M:
return 6;
case V4L2_COLORSPACE_SMPTE240M:
return 7;
case V4L2_COLORSPACE_REC709:
return 1;
case V4L2_COLORSPACE_470_SYSTEM_M:
return 4;
case V4L2_COLORSPACE_JPEG:
case V4L2_COLORSPACE_SRGB:
case V4L2_COLORSPACE_470_SYSTEM_BG:
return 5;
case V4L2_COLORSPACE_BT2020:
return 9;
case V4L2_COLORSPACE_DEFAULT:
case V4L2_COLORSPACE_OPRGB:
case V4L2_COLORSPACE_RAW:
case V4L2_COLORSPACE_DCI_P3:
default:
return 2;
}
}
static inline int nal_hevc_transfer_characteristics(enum v4l2_colorspace colorspace,
enum v4l2_xfer_func xfer_func)
{
if (xfer_func == V4L2_XFER_FUNC_DEFAULT)
xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(colorspace);
switch (xfer_func) {
case V4L2_XFER_FUNC_709:
return 6;
case V4L2_XFER_FUNC_SMPTE2084:
return 16;
case V4L2_XFER_FUNC_SRGB:
case V4L2_XFER_FUNC_OPRGB:
case V4L2_XFER_FUNC_NONE:
case V4L2_XFER_FUNC_DCI_P3:
case V4L2_XFER_FUNC_SMPTE240M:
default:
return 2;
}
}
static inline int nal_hevc_matrix_coeffs(enum v4l2_colorspace colorspace,
enum v4l2_ycbcr_encoding ycbcr_encoding)
{
if (ycbcr_encoding == V4L2_YCBCR_ENC_DEFAULT)
ycbcr_encoding = V4L2_MAP_YCBCR_ENC_DEFAULT(colorspace);
switch (ycbcr_encoding) {
case V4L2_YCBCR_ENC_601:
case V4L2_YCBCR_ENC_XV601:
return 5;
case V4L2_YCBCR_ENC_709:
case V4L2_YCBCR_ENC_XV709:
return 1;
case V4L2_YCBCR_ENC_BT2020:
return 9;
case V4L2_YCBCR_ENC_BT2020_CONST_LUM:
return 10;
case V4L2_YCBCR_ENC_SMPTE240M:
default:
return 2;
}
}
ssize_t nal_hevc_write_vps(const struct device *dev,
void *dest, size_t n, struct nal_hevc_vps *vps);
ssize_t nal_hevc_read_vps(const struct device *dev,
struct nal_hevc_vps *vps, void *src, size_t n);
ssize_t nal_hevc_write_sps(const struct device *dev,
void *dest, size_t n, struct nal_hevc_sps *sps);
ssize_t nal_hevc_read_sps(const struct device *dev,
struct nal_hevc_sps *sps, void *src, size_t n);
ssize_t nal_hevc_write_pps(const struct device *dev,
void *dest, size_t n, struct nal_hevc_pps *pps);
ssize_t nal_hevc_read_pps(const struct device *dev,
struct nal_hevc_pps *pps, void *src, size_t n);
ssize_t nal_hevc_write_filler(const struct device *dev, void *dest, size_t n);
ssize_t nal_hevc_read_filler(const struct device *dev, void *src, size_t n);
#endif /* __NAL_HEVC_H__ */
@@ -0,0 +1,310 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2019-2020 Pengutronix, Michael Tretter <kernel@pengutronix.de>
*
* Helper functions to generate a raw byte sequence payload from values.
*/
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/string.h>
#include <linux/v4l2-controls.h>
#include <linux/device.h>
#include <linux/export.h>
#include <linux/log2.h>
#include "nal-rbsp.h"
void rbsp_init(struct rbsp *rbsp, void *addr, size_t size,
struct nal_rbsp_ops *ops)
{
if (!rbsp)
return;
rbsp->data = addr;
rbsp->size = size;
rbsp->pos = 0;
rbsp->ops = ops;
rbsp->error = 0;
}
void rbsp_unsupported(struct rbsp *rbsp)
{
rbsp->error = -EINVAL;
}
static int rbsp_read_bits(struct rbsp *rbsp, int n, unsigned int *value);
static int rbsp_write_bits(struct rbsp *rbsp, int n, unsigned int value);
/*
* When reading or writing, the emulation_prevention_three_byte is detected
* only when the 2 one bits need to be inserted. Therefore, we are not
* actually adding the 0x3 byte, but the 2 one bits and the six 0 bits of the
* next byte.
*/
#define EMULATION_PREVENTION_THREE_BYTE (0x3 << 6)
static int add_emulation_prevention_three_byte(struct rbsp *rbsp)
{
rbsp->num_consecutive_zeros = 0;
rbsp_write_bits(rbsp, 8, EMULATION_PREVENTION_THREE_BYTE);
return 0;
}
static int discard_emulation_prevention_three_byte(struct rbsp *rbsp)
{
unsigned int tmp = 0;
rbsp->num_consecutive_zeros = 0;
rbsp_read_bits(rbsp, 8, &tmp);
if (tmp != EMULATION_PREVENTION_THREE_BYTE)
return -EINVAL;
return 0;
}
static inline int rbsp_read_bit(struct rbsp *rbsp)
{
int shift;
int ofs;
int bit;
int err;
if (rbsp->num_consecutive_zeros == 22) {
err = discard_emulation_prevention_three_byte(rbsp);
if (err)
return err;
}
shift = 7 - (rbsp->pos % 8);
ofs = rbsp->pos / 8;
if (ofs >= rbsp->size)
return -EINVAL;
bit = (rbsp->data[ofs] >> shift) & 1;
rbsp->pos++;
if (bit == 1 ||
(rbsp->num_consecutive_zeros < 7 && (rbsp->pos % 8 == 0)))
rbsp->num_consecutive_zeros = 0;
else
rbsp->num_consecutive_zeros++;
return bit;
}
static inline int rbsp_write_bit(struct rbsp *rbsp, bool value)
{
int shift;
int ofs;
if (rbsp->num_consecutive_zeros == 22)
add_emulation_prevention_three_byte(rbsp);
shift = 7 - (rbsp->pos % 8);
ofs = rbsp->pos / 8;
if (ofs >= rbsp->size)
return -EINVAL;
rbsp->data[ofs] &= ~(1 << shift);
rbsp->data[ofs] |= value << shift;
rbsp->pos++;
if (value ||
(rbsp->num_consecutive_zeros < 7 && (rbsp->pos % 8 == 0))) {
rbsp->num_consecutive_zeros = 0;
} else {
rbsp->num_consecutive_zeros++;
}
return 0;
}
static inline int rbsp_read_bits(struct rbsp *rbsp, int n, unsigned int *value)
{
int i;
int bit;
unsigned int tmp = 0;
if (n > 8 * sizeof(*value))
return -EINVAL;
for (i = n; i > 0; i--) {
bit = rbsp_read_bit(rbsp);
if (bit < 0)
return bit;
tmp |= bit << (i - 1);
}
if (value)
*value = tmp;
return 0;
}
static int rbsp_write_bits(struct rbsp *rbsp, int n, unsigned int value)
{
int ret;
if (n > 8 * sizeof(value))
return -EINVAL;
while (n--) {
ret = rbsp_write_bit(rbsp, (value >> n) & 1);
if (ret)
return ret;
}
return 0;
}
static int rbsp_read_uev(struct rbsp *rbsp, unsigned int *value)
{
int leading_zero_bits = 0;
unsigned int tmp = 0;
int ret;
while ((ret = rbsp_read_bit(rbsp)) == 0)
leading_zero_bits++;
if (ret < 0)
return ret;
if (leading_zero_bits > 0) {
ret = rbsp_read_bits(rbsp, leading_zero_bits, &tmp);
if (ret)
return ret;
}
if (value)
*value = (1 << leading_zero_bits) - 1 + tmp;
return 0;
}
static int rbsp_write_uev(struct rbsp *rbsp, unsigned int *value)
{
int ret;
int leading_zero_bits;
if (!value)
return -EINVAL;
leading_zero_bits = ilog2(*value + 1);
ret = rbsp_write_bits(rbsp, leading_zero_bits, 0);
if (ret)
return ret;
return rbsp_write_bits(rbsp, leading_zero_bits + 1, *value + 1);
}
static int rbsp_read_sev(struct rbsp *rbsp, int *value)
{
int ret;
unsigned int tmp;
ret = rbsp_read_uev(rbsp, &tmp);
if (ret)
return ret;
if (value) {
if (tmp & 1)
*value = (tmp + 1) / 2;
else
*value = -(tmp / 2);
}
return 0;
}
static int rbsp_write_sev(struct rbsp *rbsp, int *value)
{
unsigned int tmp;
if (!value)
return -EINVAL;
if (*value > 0)
tmp = (2 * (*value)) | 1;
else
tmp = -2 * (*value);
return rbsp_write_uev(rbsp, &tmp);
}
static int __rbsp_write_bit(struct rbsp *rbsp, int *value)
{
return rbsp_write_bit(rbsp, *value);
}
static int __rbsp_write_bits(struct rbsp *rbsp, int n, unsigned int *value)
{
return rbsp_write_bits(rbsp, n, *value);
}
struct nal_rbsp_ops write = {
.rbsp_bit = __rbsp_write_bit,
.rbsp_bits = __rbsp_write_bits,
.rbsp_uev = rbsp_write_uev,
.rbsp_sev = rbsp_write_sev,
};
static int __rbsp_read_bit(struct rbsp *rbsp, int *value)
{
int tmp = rbsp_read_bit(rbsp);
if (tmp < 0)
return tmp;
*value = tmp;
return 0;
}
struct nal_rbsp_ops read = {
.rbsp_bit = __rbsp_read_bit,
.rbsp_bits = rbsp_read_bits,
.rbsp_uev = rbsp_read_uev,
.rbsp_sev = rbsp_read_sev,
};
void rbsp_bit(struct rbsp *rbsp, int *value)
{
if (rbsp->error)
return;
rbsp->error = rbsp->ops->rbsp_bit(rbsp, value);
}
void rbsp_bits(struct rbsp *rbsp, int n, int *value)
{
if (rbsp->error)
return;
rbsp->error = rbsp->ops->rbsp_bits(rbsp, n, value);
}
void rbsp_uev(struct rbsp *rbsp, unsigned int *value)
{
if (rbsp->error)
return;
rbsp->error = rbsp->ops->rbsp_uev(rbsp, value);
}
void rbsp_sev(struct rbsp *rbsp, int *value)
{
if (rbsp->error)
return;
rbsp->error = rbsp->ops->rbsp_sev(rbsp, value);
}
void rbsp_trailing_bits(struct rbsp *rbsp)
{
unsigned int rbsp_stop_one_bit = 1;
unsigned int rbsp_alignment_zero_bit = 0;
rbsp_bit(rbsp, &rbsp_stop_one_bit);
rbsp_bits(rbsp, round_up(rbsp->pos, 8) - rbsp->pos,
&rbsp_alignment_zero_bit);
}
@@ -0,0 +1,61 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) 2019-2020 Pengutronix, Michael Tretter <kernel@pengutronix.de>
*/
#ifndef __NAL_RBSP_H__
#define __NAL_RBSP_H__
#include <linux/kernel.h>
#include <linux/types.h>
struct rbsp;
struct nal_rbsp_ops {
int (*rbsp_bit)(struct rbsp *rbsp, int *val);
int (*rbsp_bits)(struct rbsp *rbsp, int n, unsigned int *val);
int (*rbsp_uev)(struct rbsp *rbsp, unsigned int *val);
int (*rbsp_sev)(struct rbsp *rbsp, int *val);
};
/**
* struct rbsp - State object for handling a raw byte sequence payload
* @data: pointer to the data of the rbsp
* @size: maximum size of the data of the rbsp
* @pos: current bit position inside the rbsp
* @num_consecutive_zeros: number of zeros before @pos
* @ops: per datatype functions for interacting with the rbsp
* @error: an error occurred while handling the rbsp
*
* This struct is passed around the various parsing functions and tracks the
* current position within the raw byte sequence payload.
*
* The @ops field allows to separate the operation, i.e., reading/writing a
* value from/to that rbsp, from the structure of the NAL unit. This allows to
* have a single function for iterating the NAL unit, while @ops has function
* pointers for handling each type in the rbsp.
*/
struct rbsp {
u8 *data;
size_t size;
unsigned int pos;
unsigned int num_consecutive_zeros;
struct nal_rbsp_ops *ops;
int error;
};
extern struct nal_rbsp_ops write;
extern struct nal_rbsp_ops read;
void rbsp_init(struct rbsp *rbsp, void *addr, size_t size,
struct nal_rbsp_ops *ops);
void rbsp_unsupported(struct rbsp *rbsp);
void rbsp_bit(struct rbsp *rbsp, int *value);
void rbsp_bits(struct rbsp *rbsp, int n, int *value);
void rbsp_uev(struct rbsp *rbsp, unsigned int *value);
void rbsp_sev(struct rbsp *rbsp, int *value);
void rbsp_trailing_bits(struct rbsp *rbsp);
#endif /* __NAL_RBSP_H__ */