cregit-Linux how code gets into the kernel

Release 4.11 drivers/media/platform/sti/hva/hva-h264.c

/*
 * Copyright (C) STMicroelectronics SA 2015
 * Authors: Yannick Fertre <yannick.fertre@st.com>
 *          Hugues Fruchet <hugues.fruchet@st.com>
 * License terms:  GNU General Public License (GPL), version 2
 */

#include "hva.h"
#include "hva-hw.h"


#define MAX_SPS_PPS_SIZE 128


#define BITSTREAM_OFFSET_MASK 0x7F

/* video max size*/

#define H264_MAX_SIZE_W 1920

#define H264_MAX_SIZE_H 1920

/* macroBlocs number (width & height) */

#define MB_W(w) ((w + 0xF)  / 0x10)

#define MB_H(h) ((h + 0xF)  / 0x10)

/* formula to get temporal or spatial data size */

#define DATA_SIZE(w, h) (MB_W(w) * MB_H(h) * 16)


#define SEARCH_WINDOW_BUFFER_MAX_SIZE(w) ((4 * MB_W(w) + 42) * 256 * 3 / 2)

#define CABAC_CONTEXT_BUFFER_MAX_SIZE(w) (MB_W(w) * 16)

#define CTX_MB_BUFFER_MAX_SIZE(w) (MB_W(w) * 16 * 8)

#define SLICE_HEADER_SIZE (4 * 16)

#define BRC_DATA_SIZE (5 * 16)

/* source buffer copy in YUV 420 MB-tiled format with size=16*256*3/2 */

#define CURRENT_WINDOW_BUFFER_MAX_SIZE (16 * 256 * 3 / 2)

/*
 * 4 lines of pixels (in Luma, Chroma blue and Chroma red) of top MB
 * for deblocking with size=4*16*MBx*2
 */

#define LOCAL_RECONSTRUCTED_BUFFER_MAX_SIZE(w) (4 * 16 * MB_W(w) * 2)

/* factor for bitrate and cpb buffer size max values if profile >= high */

#define H264_FACTOR_HIGH 1200

/* factor for bitrate and cpb buffer size max values if profile < high */

#define H264_FACTOR_BASELINE 1000

/* number of bytes for NALU_TYPE_FILLER_DATA header and footer */

#define H264_FILLER_DATA_SIZE 6


struct h264_profile {
	
enum v4l2_mpeg_video_h264_level level;
	
u32 max_mb_per_seconds;
	
u32 max_frame_size;
	
u32 max_bitrate;
	
u32 max_cpb_size;
	
u32 min_comp_ratio;
};


static const struct h264_profile h264_infos_list[] = {
	{V4L2_MPEG_VIDEO_H264_LEVEL_1_0, 1485, 99, 64, 175, 2},
	{V4L2_MPEG_VIDEO_H264_LEVEL_1B, 1485, 99, 128, 350, 2},
	{V4L2_MPEG_VIDEO_H264_LEVEL_1_1, 3000, 396, 192, 500, 2},
	{V4L2_MPEG_VIDEO_H264_LEVEL_1_2, 6000, 396, 384, 1000, 2},
	{V4L2_MPEG_VIDEO_H264_LEVEL_1_3, 11880, 396, 768, 2000, 2},
	{V4L2_MPEG_VIDEO_H264_LEVEL_2_0, 11880, 396, 2000, 2000, 2},
	{V4L2_MPEG_VIDEO_H264_LEVEL_2_1, 19800, 792, 4000, 4000, 2},
	{V4L2_MPEG_VIDEO_H264_LEVEL_2_2, 20250, 1620, 4000, 4000, 2},
	{V4L2_MPEG_VIDEO_H264_LEVEL_3_0, 40500, 1620, 10000, 10000, 2},
	{V4L2_MPEG_VIDEO_H264_LEVEL_3_1, 108000, 3600, 14000, 14000, 4},
	{V4L2_MPEG_VIDEO_H264_LEVEL_3_2, 216000, 5120, 20000, 20000, 4},
	{V4L2_MPEG_VIDEO_H264_LEVEL_4_0, 245760, 8192, 20000, 25000, 4},
	{V4L2_MPEG_VIDEO_H264_LEVEL_4_1, 245760, 8192, 50000, 62500, 2},
	{V4L2_MPEG_VIDEO_H264_LEVEL_4_2, 522240, 8704, 50000, 62500, 2},
	{V4L2_MPEG_VIDEO_H264_LEVEL_5_0, 589824, 22080, 135000, 135000, 2},
	{V4L2_MPEG_VIDEO_H264_LEVEL_5_1, 983040, 36864, 240000, 240000, 2}
};


enum hva_brc_type {
	
BRC_TYPE_NONE = 0,
	
BRC_TYPE_CBR = 1,
	
BRC_TYPE_VBR = 2,
	
BRC_TYPE_VBR_LOW_DELAY = 3
};


enum hva_entropy_coding_mode {
	
CAVLC = 0,
	
CABAC = 1
};


enum hva_picture_coding_type {
	
PICTURE_CODING_TYPE_I = 0,
	
PICTURE_CODING_TYPE_P = 1,
	
PICTURE_CODING_TYPE_B = 2
};


enum hva_h264_sampling_mode {
	
SAMPLING_MODE_NV12 = 0,
	
SAMPLING_MODE_UYVY = 1,
	
SAMPLING_MODE_RGB3 = 3,
	
SAMPLING_MODE_XRGB4 = 4,
	
SAMPLING_MODE_NV21 = 8,
	
SAMPLING_MODE_VYUY = 9,
	
SAMPLING_MODE_BGR3 = 11,
	
SAMPLING_MODE_XBGR4 = 12,
	
SAMPLING_MODE_RGBX4 = 20,
	
SAMPLING_MODE_BGRX4 = 28
};


enum hva_h264_nalu_type {
	
NALU_TYPE_UNKNOWN = 0,
	
NALU_TYPE_SLICE = 1,
	
NALU_TYPE_SLICE_DPA = 2,
	
NALU_TYPE_SLICE_DPB = 3,
	
NALU_TYPE_SLICE_DPC = 4,
	
NALU_TYPE_SLICE_IDR = 5,
	
NALU_TYPE_SEI = 6,
	
NALU_TYPE_SPS = 7,
	
NALU_TYPE_PPS = 8,
	
NALU_TYPE_AU_DELIMITER = 9,
	
NALU_TYPE_SEQ_END = 10,
	
NALU_TYPE_STREAM_END = 11,
	
NALU_TYPE_FILLER_DATA = 12,
	
NALU_TYPE_SPS_EXT = 13,
	
NALU_TYPE_PREFIX_UNIT = 14,
	
NALU_TYPE_SUBSET_SPS = 15,
	
NALU_TYPE_SLICE_AUX = 19,
	
NALU_TYPE_SLICE_EXT = 20
};


enum hva_h264_sei_payload_type {
	
SEI_BUFFERING_PERIOD = 0,
	
SEI_PICTURE_TIMING = 1,
	
SEI_STEREO_VIDEO_INFO = 21,
	
SEI_FRAME_PACKING_ARRANGEMENT = 45
};

/**
 * stereo Video Info struct
 */

struct hva_h264_stereo_video_sei {
	
u8 field_views_flag;
	
u8 top_field_is_left_view_flag;
	
u8 current_frame_is_left_view_flag;
	
u8 next_frame_is_second_view_flag;
	
u8 left_view_self_contained_flag;
	
u8 right_view_self_contained_flag;
};

/**
 * @frame_width: width in pixels of the buffer containing the input frame
 * @frame_height: height in pixels of the buffer containing the input frame
 * @frame_num: the parameter to be written in the slice header
 * @picture_coding_type: type I, P or B
 * @pic_order_cnt_type: POC mode, as defined in H264 std : can be 0,1,2
 * @first_picture_in_sequence: flag telling to encoder that this is the
 *                             first picture in a video sequence.
 *                             Used for VBR
 * @slice_size_type: 0 = no constraint to close the slice
 *                   1= a slice is closed as soon as the slice_mb_size limit
 *                      is reached
 *                   2= a slice is closed as soon as the slice_byte_size limit
 *                      is reached
 *                   3= a slice is closed as soon as either the slice_byte_size
 *                      limit or the slice_mb_size limit is reached
 * @slice_mb_size: defines the slice size in number of macroblocks
 *                 (used when slice_size_type=1 or slice_size_type=3)
 * @ir_param_option: defines the number of macroblocks per frame to be
 *                   refreshed by AIR algorithm OR the refresh period
 *                   by CIR algorithm
 * @intra_refresh_type: enables the adaptive intra refresh algorithm.
 *                      Disable=0 / Adaptative=1 and Cycle=2 as intra refresh
 * @use_constrained_intra_flag: constrained_intra_pred_flag from PPS
 * @transform_mode: controls the use of 4x4/8x8 transform mode
 * @disable_deblocking_filter_idc:
 *                   0: specifies that all luma and chroma block edges of
 *                      the slice are filtered.
 *                   1: specifies that deblocking is disabled for all block
 *                      edges of the slice.
 *                   2: specifies that all luma and chroma block edges of
 *                      the slice are filtered with exception of the block edges
 *                      that coincide with slice boundaries
 * @slice_alpha_c0_offset_div2: to be written in slice header,
 *                              controls deblocking
 * @slice_beta_offset_div2: to be written in slice header,
 *                          controls deblocking
 * @encoder_complexity: encoder complexity control (IME).
 *                   0 = I_16x16, P_16x16, Full ME Complexity
 *                   1 = I_16x16, I_NxN, P_16x16, Full ME Complexity
 *                   2 = I_16x16, I_NXN, P_16x16, P_WxH, Full ME Complexity
 *                   4 = I_16x16, P_16x16, Reduced ME Complexity
 *                   5 = I_16x16, I_NxN, P_16x16, Reduced ME Complexity
 *                   6 = I_16x16, I_NXN, P_16x16, P_WxH, Reduced ME Complexity
 *  @chroma_qp_index_offset: coming from picture parameter set
 *                           (PPS see [H.264 STD] 7.4.2.2)
 *  @entropy_coding_mode: entropy coding mode.
 *                        0 = CAVLC
 *                        1 = CABAC
 * @brc_type: selects the bit-rate control algorithm
 *                   0 = constant Qp, (no BRC)
 *                   1 = CBR
 *                   2 = VBR
 * @quant: Quantization param used in case of fix QP encoding (no BRC)
 * @non_VCL_NALU_Size: size of non-VCL NALUs (SPS, PPS, filler),
 *                     used by BRC
 * @cpb_buffer_size: size of Coded Picture Buffer, used by BRC
 * @bit_rate: target bitrate, for BRC
 * @qp_min: min QP threshold
 * @qp_max: max QP threshold
 * @framerate_num: target framerate numerator , used by BRC
 * @framerate_den: target framerate denomurator , used by BRC
 * @delay: End-to-End Initial Delay
 * @strict_HRD_compliancy: flag for HDR compliancy (1)
 *                         May impact quality encoding
 * @addr_source_buffer: address of input frame buffer for current frame
 * @addr_fwd_Ref_Buffer: address of reference frame buffer
 * @addr_rec_buffer: address of reconstructed frame buffer
 * @addr_output_bitstream_start: output bitstream start address
 * @addr_output_bitstream_end: output bitstream end address
 * @addr_external_sw : address of external search window
 * @addr_lctx : address of context picture buffer
 * @addr_local_rec_buffer: address of local reconstructed buffer
 * @addr_spatial_context: address of spatial context buffer
 * @bitstream_offset: offset in bits between aligned bitstream start
 *                    address and first bit to be written by HVA.
 *                    Range value is [0..63]
 * @sampling_mode: Input picture format .
 *                   0: YUV420 semi_planar Interleaved
 *                   1: YUV422 raster Interleaved
 * @addr_param_out: address of output parameters structure
 * @addr_scaling_matrix: address to the coefficient of
 *                       the inverse scaling matrix
 * @addr_scaling_matrix_dir: address to the coefficient of
 *                           the direct scaling matrix
 * @addr_cabac_context_buffer: address of cabac context buffer
 * @GmvX: Input information about the horizontal global displacement of
 *        the encoded frame versus the previous one
 * @GmvY: Input information about the vertical global displacement of
 *        the encoded frame versus the previous one
 * @window_width: width in pixels of the window to be encoded inside
 *                the input frame
 * @window_height: width in pixels of the window to be encoded inside
 *                 the input frame
 * @window_horizontal_offset: horizontal offset in pels for input window
 *                            within input frame
 * @window_vertical_offset: vertical offset in pels for input window
 *                          within input frame
 * @addr_roi: Map of QP offset for the Region of Interest algorithm and
 *            also used for Error map.
 *            Bit 0-6 used for qp offset (value -64 to 63).
 *            Bit 7 used to force intra
 * @addr_slice_header: address to slice header
 * @slice_header_size_in_bits: size in bits of the Slice header
 * @slice_header_offset0: Slice header offset where to insert
 *                        first_Mb_in_slice
 * @slice_header_offset1: Slice header offset where to insert
 *                        slice_qp_delta
 * @slice_header_offset2: Slice header offset where to insert
 *                        num_MBs_in_slice
 * @slice_synchro_enable: enable "slice ready" interrupt after each slice
 * @max_slice_number: Maximum number of slice in a frame
 *                    (0 is strictly forbidden)
 * @rgb2_yuv_y_coeff: Four coefficients (C0C1C2C3) to convert from RGB to
 *                    YUV for the Y component.
 *                    Y = C0*R + C1*G + C2*B + C3 (C0 is on byte 0)
 * @rgb2_yuv_u_coeff: four coefficients (C0C1C2C3) to convert from RGB to
 *                    YUV for the Y component.
 *                    Y = C0*R + C1*G + C2*B + C3 (C0 is on byte 0)
 * @rgb2_yuv_v_coeff: Four coefficients (C0C1C2C3) to convert from RGB to
 *                    YUV for the U (Cb) component.
 *                    U = C0*R + C1*G + C2*B + C3 (C0 is on byte 0)
 * @slice_byte_size: maximum slice size in bytes
 *                   (used when slice_size_type=2 or slice_size_type=3)
 * @max_air_intra_mb_nb: Maximum number of intra macroblock in a frame
 *                       for the AIR algorithm
 * @brc_no_skip: Disable skipping in the Bitrate Controller
 * @addr_brc_in_out_parameter: address of static buffer for BRC parameters
 */

struct hva_h264_td {
	
u16 frame_width;
	
u16 frame_height;
	
u32 frame_num;
	
u16 picture_coding_type;
	
u16 reserved1;
	
u16 pic_order_cnt_type;
	
u16 first_picture_in_sequence;
	
u16 slice_size_type;
	
u16 reserved2;
	
u32 slice_mb_size;
	
u16 ir_param_option;
	
u16 intra_refresh_type;
	
u16 use_constrained_intra_flag;
	
u16 transform_mode;
	
u16 disable_deblocking_filter_idc;
	
s16 slice_alpha_c0_offset_div2;
	
s16 slice_beta_offset_div2;
	
u16 encoder_complexity;
	
s16 chroma_qp_index_offset;
	
u16 entropy_coding_mode;
	
u16 brc_type;
	
u16 quant;
	
u32 non_vcl_nalu_size;
	
u32 cpb_buffer_size;
	
u32 bit_rate;
	
u16 qp_min;
	
u16 qp_max;
	
u16 framerate_num;
	
u16 framerate_den;
	
u16 delay;
	
u16 strict_hrd_compliancy;
	
u32 addr_source_buffer;
	
u32 addr_fwd_ref_buffer;
	
u32 addr_rec_buffer;
	
u32 addr_output_bitstream_start;
	
u32 addr_output_bitstream_end;
	
u32 addr_external_sw;
	
u32 addr_lctx;
	
u32 addr_local_rec_buffer;
	
u32 addr_spatial_context;
	
u16 bitstream_offset;
	
u16 sampling_mode;
	
u32 addr_param_out;
	
u32 addr_scaling_matrix;
	
u32 addr_scaling_matrix_dir;
	
u32 addr_cabac_context_buffer;
	
u32 reserved3;
	
u32 reserved4;
	
s16 gmv_x;
	
s16 gmv_y;
	
u16 window_width;
	
u16 window_height;
	
u16 window_horizontal_offset;
	
u16 window_vertical_offset;
	
u32 addr_roi;
	
u32 addr_slice_header;
	
u16 slice_header_size_in_bits;
	
u16 slice_header_offset0;
	
u16 slice_header_offset1;
	
u16 slice_header_offset2;
	
u32 reserved5;
	
u32 reserved6;
	
u16 reserved7;
	
u16 reserved8;
	
u16 slice_synchro_enable;
	
u16 max_slice_number;
	
u32 rgb2_yuv_y_coeff;
	
u32 rgb2_yuv_u_coeff;
	
u32 rgb2_yuv_v_coeff;
	
u32 slice_byte_size;
	
u16 max_air_intra_mb_nb;
	
u16 brc_no_skip;
	
u32 addr_temporal_context;
	
u32 addr_brc_in_out_parameter;
};

/**
 * @ slice_size: slice size
 * @ slice_start_time: start time
 * @ slice_stop_time: stop time
 * @ slice_num: slice number
 */

struct hva_h264_slice_po {
	
u32 slice_size;
	
u32 slice_start_time;
	
u32 slice_end_time;
	
u32 slice_num;
};

/**
 * @ bitstream_size: bitstream size
 * @ dct_bitstream_size: dtc bitstream size
 * @ stuffing_bits: number of stuffing bits inserted by the encoder
 * @ removal_time: removal time of current frame (nb of ticks 1/framerate)
 * @ hvc_start_time: hvc start time
 * @ hvc_stop_time: hvc stop time
 * @ slice_count: slice count
 */

struct hva_h264_po {
	
u32 bitstream_size;
	
u32 dct_bitstream_size;
	
u32 stuffing_bits;
	
u32 removal_time;
	
u32 hvc_start_time;
	
u32 hvc_stop_time;
	
u32 slice_count;
	
u32 reserved0;
	
struct hva_h264_slice_po slice_params[16];
};


struct hva_h264_task {
	
struct hva_h264_td td;
	
struct hva_h264_po po;
};

/**
 * @seq_info:  sequence information buffer
 * @ref_frame: reference frame buffer
 * @rec_frame: reconstructed frame buffer
 * @task:      task descriptor
 */

struct hva_h264_ctx {
	
struct hva_buffer *seq_info;
	
struct hva_buffer *ref_frame;
	
struct hva_buffer *rec_frame;
	
struct hva_buffer *task;
};


static int hva_h264_fill_slice_header(struct hva_ctx *pctx, u8 *slice_header_addr, struct hva_controls *ctrls, int frame_num, u16 *header_size, u16 *header_offset0, u16 *header_offset1, u16 *header_offset2) { /* * with this HVA hardware version, part of the slice header is computed * on host and part by hardware. * The part of host is precomputed and available through this array. */ struct device *dev = ctx_to_dev(pctx); int cabac = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC; const unsigned char slice_header[] = { 0x00, 0x00, 0x00, 0x01, 0x41, 0x34, 0x07, 0x00}; int idr_pic_id = frame_num % 2; enum hva_picture_coding_type type; u32 frame_order = frame_num % ctrls->gop_size; if (!(frame_num % ctrls->gop_size)) type = PICTURE_CODING_TYPE_I; else type = PICTURE_CODING_TYPE_P; memcpy(slice_header_addr, slice_header, sizeof(slice_header)); *header_size = 56; *header_offset0 = 40; *header_offset1 = 13; *header_offset2 = 0; if (type == PICTURE_CODING_TYPE_I) { slice_header_addr[4] = 0x65; slice_header_addr[5] = 0x11; /* toggle the I frame */ if ((frame_num / ctrls->gop_size) % 2) { *header_size += 4; *header_offset1 += 4; slice_header_addr[6] = 0x04; slice_header_addr[7] = 0x70; } else { *header_size += 2; *header_offset1 += 2; slice_header_addr[6] = 0x09; slice_header_addr[7] = 0xC0; } } else { if (ctrls->entropy_mode == cabac) { *header_size += 1; *header_offset1 += 1; slice_header_addr[7] = 0x80; } /* * update slice header with P frame order * frame order is limited to 16 (coded on 4bits only) */ slice_header_addr[5] += ((frame_order & 0x0C) >> 2); slice_header_addr[6] += ((frame_order & 0x03) << 6); } dev_dbg(dev, "%s %s slice header order %d idrPicId %d header size %d\n", pctx->name, __func__, frame_order, idr_pic_id, *header_size); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Jean-Christophe Trotin323100.00%1100.00%
Total323100.00%1100.00%


static int hva_h264_fill_data_nal(struct hva_ctx *pctx, unsigned int stuffing_bytes, u8 *addr, unsigned int stream_size, unsigned int *size) { struct device *dev = ctx_to_dev(pctx); const u8 start[] = { 0x00, 0x00, 0x00, 0x01 }; dev_dbg(dev, "%s %s stuffing bytes %d\n", pctx->name, __func__, stuffing_bytes); if ((*size + stuffing_bytes + H264_FILLER_DATA_SIZE) > stream_size) { dev_dbg(dev, "%s %s too many stuffing bytes %d\n", pctx->name, __func__, stuffing_bytes); return 0; } /* start code */ memcpy(addr + *size, start, sizeof(start)); *size += sizeof(start); /* nal_unit_type */ addr[*size] = NALU_TYPE_FILLER_DATA; *size += 1; memset(addr + *size, 0xff, stuffing_bytes); *size += stuffing_bytes; addr[*size] = 0x80; *size += 1; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Jean-Christophe Trotin172100.00%1100.00%
Total172100.00%1100.00%


static int hva_h264_fill_sei_nal(struct hva_ctx *pctx, enum hva_h264_sei_payload_type type, u8 *addr, u32 *size) { struct device *dev = ctx_to_dev(pctx); const u8 start[] = { 0x00, 0x00, 0x00, 0x01 }; struct hva_h264_stereo_video_sei info; u8 offset = 7; u8 msg = 0; /* start code */ memcpy(addr + *size, start, sizeof(start)); *size += sizeof(start); /* nal_unit_type */ addr[*size] = NALU_TYPE_SEI; *size += 1; /* payload type */ addr[*size] = type; *size += 1; switch (type) { case SEI_STEREO_VIDEO_INFO: memset(&info, 0, sizeof(info)); /* set to top/bottom frame packing arrangement */ info.field_views_flag = 1; info.top_field_is_left_view_flag = 1; /* payload size */ addr[*size] = 1; *size += 1; /* payload */ msg = info.field_views_flag << offset--; if (info.field_views_flag) { msg |= info.top_field_is_left_view_flag << offset--; } else { msg |= info.current_frame_is_left_view_flag << offset--; msg |= info.next_frame_is_second_view_flag << offset--; } msg |= info.left_view_self_contained_flag << offset--; msg |= info.right_view_self_contained_flag << offset--; addr[*size] = msg; *size += 1; addr[*size] = 0x80; *size += 1; return 0; case SEI_BUFFERING_PERIOD: case SEI_PICTURE_TIMING: case SEI_FRAME_PACKING_ARRANGEMENT: default: dev_err(dev, "%s sei nal type not supported %d\n", pctx->name, type); return -EINVAL; } }

Contributors

PersonTokensPropCommitsCommitProp
Jean-Christophe Trotin285100.00%1100.00%
Total285100.00%1100.00%


static int hva_h264_prepare_task(struct hva_ctx *pctx, struct hva_h264_task *task, struct hva_frame *frame, struct hva_stream *stream) { struct hva_dev *hva = ctx_to_hdev(pctx); struct device *dev = ctx_to_dev(pctx); struct hva_h264_ctx *ctx = (struct hva_h264_ctx *)pctx->priv; struct hva_buffer *seq_info = ctx->seq_info; struct hva_buffer *fwd_ref_frame = ctx->ref_frame; struct hva_buffer *loc_rec_frame = ctx->rec_frame; struct hva_h264_td *td = &task->td; struct hva_controls *ctrls = &pctx->ctrls; struct v4l2_fract *time_per_frame = &pctx->ctrls.time_per_frame; int cavlc = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC; u32 frame_num = pctx->stream_num; u32 addr_esram = hva->esram_addr; enum v4l2_mpeg_video_h264_level level; dma_addr_t paddr = 0; u8 *slice_header_vaddr; u32 frame_width = frame->info.aligned_width; u32 frame_height = frame->info.aligned_height; u32 max_cpb_buffer_size; unsigned int payload = stream->bytesused; u32 max_bitrate; /* check width and height parameters */ if ((frame_width > max(H264_MAX_SIZE_W, H264_MAX_SIZE_H)) || (frame_height > max(H264_MAX_SIZE_W, H264_MAX_SIZE_H))) { dev_err(dev, "%s width(%d) or height(%d) exceeds limits (%dx%d)\n", pctx->name, frame_width, frame_height, H264_MAX_SIZE_W, H264_MAX_SIZE_H); pctx->frame_errors++; return -EINVAL; } level = ctrls->level; memset(td, 0, sizeof(struct hva_h264_td)); td->frame_width = frame_width; td->frame_height = frame_height; /* set frame alignement */ td->window_width = frame_width; td->window_height = frame_height; td->window_horizontal_offset = 0; td->window_vertical_offset = 0; td->first_picture_in_sequence = (!frame_num) ? 1 : 0; /* pic_order_cnt_type hard coded to '2' as only I & P frames */ td->pic_order_cnt_type = 2; /* useConstrainedIntraFlag set to false for better coding efficiency */ td->use_constrained_intra_flag = false; td->brc_type = (ctrls->bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR) ? BRC_TYPE_CBR : BRC_TYPE_VBR; td->entropy_coding_mode = (ctrls->entropy_mode == cavlc) ? CAVLC : CABAC; td->bit_rate = ctrls->bitrate; /* set framerate, framerate = 1 n/ time per frame */ if (time_per_frame->numerator >= 536) { /* * due to a hardware bug, framerate denominator can't exceed * 536 (BRC overflow). Compute nearest framerate */ td->framerate_den = 1; td->framerate_num = (time_per_frame->denominator + (time_per_frame->numerator >> 1) - 1) / time_per_frame->numerator; /* * update bitrate to introduce a correction due to * the new framerate * new bitrate = (old bitrate * new framerate) / old framerate */ td->bit_rate /= time_per_frame->numerator; td->bit_rate *= time_per_frame->denominator; td->bit_rate /= td->framerate_num; } else { td->framerate_den = time_per_frame->numerator; td->framerate_num = time_per_frame->denominator; } /* compute maximum bitrate depending on profile */ if (ctrls->profile >= V4L2_MPEG_VIDEO_H264_PROFILE_HIGH) max_bitrate = h264_infos_list[level].max_bitrate * H264_FACTOR_HIGH; else max_bitrate = h264_infos_list[level].max_bitrate * H264_FACTOR_BASELINE; /* check if bitrate doesn't exceed max size */ if (td->bit_rate > max_bitrate) { dev_dbg(dev, "%s bitrate (%d) larger than level and profile allow, clip to %d\n", pctx->name, td->bit_rate, max_bitrate); td->bit_rate = max_bitrate; } /* convert cpb_buffer_size in bits */ td->cpb_buffer_size = ctrls->cpb_size * 8000; /* compute maximum cpb buffer size depending on profile */ if (ctrls->profile >= V4L2_MPEG_VIDEO_H264_PROFILE_HIGH) max_cpb_buffer_size = h264_infos_list[level].max_cpb_size * H264_FACTOR_HIGH; else max_cpb_buffer_size = h264_infos_list[level].max_cpb_size * H264_FACTOR_BASELINE; /* check if cpb buffer size doesn't exceed max size */ if (td->cpb_buffer_size > max_cpb_buffer_size) { dev_dbg(dev, "%s cpb size larger than level %d allows, clip to %d\n", pctx->name, td->cpb_buffer_size, max_cpb_buffer_size); td->cpb_buffer_size = max_cpb_buffer_size; } /* enable skipping in the Bitrate Controller */ td->brc_no_skip = 0; /* initial delay */ if ((ctrls->bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR) && td->bit_rate) td->delay = 1000 * (td->cpb_buffer_size / td->bit_rate); else td->delay = 0; switch (frame->info.pixelformat) { case V4L2_PIX_FMT_NV12: td->sampling_mode = SAMPLING_MODE_NV12; break; case V4L2_PIX_FMT_NV21: td->sampling_mode = SAMPLING_MODE_NV21; break; default: dev_err(dev, "%s invalid source pixel format\n", pctx->name); pctx->frame_errors++; return -EINVAL; } /* * fill matrix color converter (RGB to YUV) * Y = 0,299 R + 0,587 G + 0,114 B * Cb = -0,1687 R -0,3313 G + 0,5 B + 128 * Cr = 0,5 R - 0,4187 G - 0,0813 B + 128 */ td->rgb2_yuv_y_coeff = 0x12031008; td->rgb2_yuv_u_coeff = 0x800EF7FB; td->rgb2_yuv_v_coeff = 0x80FEF40E; /* enable/disable transform mode */ td->transform_mode = ctrls->dct8x8; /* encoder complexity fix to 2, ENCODE_I_16x16_I_NxN_P_16x16_P_WxH */ td->encoder_complexity = 2; /* quant fix to 28, default VBR value */ td->quant = 28; if (td->framerate_den == 0) { dev_err(dev, "%s invalid framerate\n", pctx->name); pctx->frame_errors++; return -EINVAL; } /* if automatic framerate, deactivate bitrate controller */ if (td->framerate_num == 0) td->brc_type = 0; /* compliancy fix to true */ td->strict_hrd_compliancy = 1; /* set minimum & maximum quantizers */ td->qp_min = clamp_val(ctrls->qpmin, 0, 51); td->qp_max = clamp_val(ctrls->qpmax, 0, 51); td->addr_source_buffer = frame->paddr; td->addr_fwd_ref_buffer = fwd_ref_frame->paddr; td->addr_rec_buffer = loc_rec_frame->paddr; td->addr_output_bitstream_end = (u32)stream->paddr + stream->size; td->addr_output_bitstream_start = (u32)stream->paddr; td->bitstream_offset = (((u32)stream->paddr & 0xF) << 3) & BITSTREAM_OFFSET_MASK; td->addr_param_out = (u32)ctx->task->paddr + offsetof(struct hva_h264_task, po); /* swap spatial and temporal context */ if (frame_num % 2) { paddr = seq_info->paddr; td->addr_spatial_context = ALIGN(paddr, 0x100); paddr = seq_info->paddr + DATA_SIZE(frame_width, frame_height); td->addr_temporal_context = ALIGN(paddr, 0x100); } else { paddr = seq_info->paddr; td->addr_temporal_context = ALIGN(paddr, 0x100); paddr = seq_info->paddr + DATA_SIZE(frame_width, frame_height); td->addr_spatial_context = ALIGN(paddr, 0x100); } paddr = seq_info->paddr + 2 * DATA_SIZE(frame_width, frame_height); td->addr_brc_in_out_parameter = ALIGN(paddr, 0x100); paddr = td->addr_brc_in_out_parameter + BRC_DATA_SIZE; td->addr_slice_header = ALIGN(paddr, 0x100); td->addr_external_sw = ALIGN(addr_esram, 0x100); addr_esram += SEARCH_WINDOW_BUFFER_MAX_SIZE(frame_width); td->addr_local_rec_buffer = ALIGN(addr_esram, 0x100); addr_esram += LOCAL_RECONSTRUCTED_BUFFER_MAX_SIZE(frame_width); td->addr_lctx = ALIGN(addr_esram, 0x100); addr_esram += CTX_MB_BUFFER_MAX_SIZE(max(frame_width, frame_height)); td->addr_cabac_context_buffer = ALIGN(addr_esram, 0x100); if (!(frame_num % ctrls->gop_size)) { td->picture_coding_type = PICTURE_CODING_TYPE_I; stream->vbuf.flags |= V4L2_BUF_FLAG_KEYFRAME; } else { td->picture_coding_type = PICTURE_CODING_TYPE_P; stream->vbuf.flags &= ~V4L2_BUF_FLAG_KEYFRAME; } /* fill the slice header part */ slice_header_vaddr = seq_info->vaddr + (td->addr_slice_header - seq_info->paddr); hva_h264_fill_slice_header(pctx, slice_header_vaddr, ctrls, frame_num, &td->slice_header_size_in_bits, &td->slice_header_offset0, &td->slice_header_offset1, &td->slice_header_offset2); td->chroma_qp_index_offset = 2; td->slice_synchro_enable = 0; td->max_slice_number = 1; /* * check the sps/pps header size for key frame only * sps/pps header was previously fill by libv4l * during qbuf of stream buffer */ if ((stream->vbuf.flags == V4L2_BUF_FLAG_KEYFRAME) && (payload > MAX_SPS_PPS_SIZE)) { dev_err(dev, "%s invalid sps/pps size %d\n", pctx->name, payload); pctx->frame_errors++; return -EINVAL; } if (stream->vbuf.flags != V4L2_BUF_FLAG_KEYFRAME) payload = 0; /* add SEI nal (video stereo info) */ if (ctrls->sei_fp && hva_h264_fill_sei_nal(pctx, SEI_STEREO_VIDEO_INFO, (u8 *)stream->vaddr, &payload)) { dev_err(dev, "%s fail to get SEI nal\n", pctx->name); pctx->frame_errors++; return -EINVAL; } /* fill size of non-VCL NAL units (SPS, PPS, filler and SEI) */ td->non_vcl_nalu_size = payload * 8; /* compute bitstream offset & new start address of bitstream */ td->addr_output_bitstream_start += ((payload >> 4) << 4); td->bitstream_offset += (payload - ((payload >> 4) << 4)) * 8; stream->bytesused = payload; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Jean-Christophe Trotin1380100.00%2100.00%
Total1380100.00%2100.00%


static unsigned int hva_h264_get_stream_size(struct hva_h264_task *task) { struct hva_h264_po *po = &task->po; return po->bitstream_size; }

Contributors

PersonTokensPropCommitsCommitProp
Jean-Christophe Trotin27100.00%1100.00%
Total27100.00%1100.00%


static u32 hva_h264_get_stuffing_bytes(struct hva_h264_task *task) { struct hva_h264_po *po = &task->po; return po->stuffing_bits >> 3; }

Contributors

PersonTokensPropCommitsCommitProp
Jean-Christophe Trotin28100.00%1100.00%
Total28100.00%1100.00%


static int hva_h264_open(struct hva_ctx *pctx) { struct device *dev = ctx_to_dev(pctx); struct hva_h264_ctx *ctx; struct hva_dev *hva = ctx_to_hdev(pctx); u32 frame_width = pctx->frameinfo.aligned_width; u32 frame_height = pctx->frameinfo.aligned_height; u32 size; int ret; /* check esram size necessary to encode a frame */ size = SEARCH_WINDOW_BUFFER_MAX_SIZE(frame_width) + LOCAL_RECONSTRUCTED_BUFFER_MAX_SIZE(frame_width) + CTX_MB_BUFFER_MAX_SIZE(max(frame_width, frame_height)) + CABAC_CONTEXT_BUFFER_MAX_SIZE(frame_width); if (hva->esram_size < size) { dev_err(dev, "%s not enough esram (max:%d request:%d)\n", pctx->name, hva->esram_size, size); ret = -EINVAL; goto err; } /* allocate context for codec */ ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); if (!ctx) { ret = -ENOMEM; goto err; } /* allocate sequence info buffer */ ret = hva_mem_alloc(pctx, 2 * DATA_SIZE(frame_width, frame_height) + SLICE_HEADER_SIZE + BRC_DATA_SIZE, "hva sequence info", &ctx->seq_info); if (ret) { dev_err(dev, "%s failed to allocate sequence info buffer\n", pctx->name); goto err_ctx; } /* allocate reference frame buffer */ ret = hva_mem_alloc(pctx, frame_width * frame_height * 3 / 2, "hva reference frame", &ctx->ref_frame); if (ret) { dev_err(dev, "%s failed to allocate reference frame buffer\n", pctx->name); goto err_seq_info; } /* allocate reconstructed frame buffer */ ret = hva_mem_alloc(pctx, frame_width * frame_height * 3 / 2, "hva reconstructed frame", &ctx->rec_frame); if (ret) { dev_err(dev, "%s failed to allocate reconstructed frame buffer\n", pctx->name); goto err_ref_frame; } /* allocate task descriptor */ ret = hva_mem_alloc(pctx, sizeof(struct hva_h264_task), "hva task descriptor", &ctx->task); if (ret) { dev_err(dev, "%s failed to allocate task descriptor\n", pctx->name); goto err_rec_frame; } pctx->priv = (void *)ctx; return 0; err_rec_frame: hva_mem_free(pctx, ctx->rec_frame); err_ref_frame: hva_mem_free(pctx, ctx->ref_frame); err_seq_info: hva_mem_free(pctx, ctx->seq_info); err_ctx: devm_kfree(dev, ctx); err: pctx->sys_errors++; return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Jean-Christophe Trotin394100.00%2100.00%
Total394100.00%2100.00%


static int hva_h264_close(struct hva_ctx *pctx) { struct hva_h264_ctx *ctx = (struct hva_h264_ctx *)pctx->priv; struct device *dev = ctx_to_dev(pctx); if (ctx->seq_info) hva_mem_free(pctx, ctx->seq_info); if (ctx->ref_frame) hva_mem_free(pctx, ctx->ref_frame); if (ctx->rec_frame) hva_mem_free(pctx, ctx->rec_frame); if (ctx->task) hva_mem_free(pctx, ctx->task); devm_kfree(dev, ctx); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Jean-Christophe Trotin105100.00%1100.00%
Total105100.00%1100.00%


static int hva_h264_encode(struct hva_ctx *pctx, struct hva_frame *frame, struct hva_stream *stream) { struct hva_h264_ctx *ctx = (struct hva_h264_ctx *)pctx->priv; struct hva_h264_task *task = (struct hva_h264_task *)ctx->task->vaddr; struct hva_buffer *tmp_frame; u32 stuffing_bytes = 0; int ret = 0; ret = hva_h264_prepare_task(pctx, task, frame, stream); if (ret) goto err; ret = hva_hw_execute_task(pctx, H264_ENC, ctx->task); if (ret) goto err; pctx->stream_num++; stream->bytesused += hva_h264_get_stream_size(task); stuffing_bytes = hva_h264_get_stuffing_bytes(task); if (stuffing_bytes) hva_h264_fill_data_nal(pctx, stuffing_bytes, (u8 *)stream->vaddr, stream->size, &stream->bytesused); /* switch reference & reconstructed frame */ tmp_frame = ctx->ref_frame; ctx->ref_frame = ctx->rec_frame; ctx->rec_frame = tmp_frame; return 0; err: stream->bytesused = 0; return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Jean-Christophe Trotin190100.00%1100.00%
Total190100.00%1100.00%

const struct hva_enc nv12h264enc = { .name = "H264(NV12)", .pixelformat = V4L2_PIX_FMT_NV12, .streamformat = V4L2_PIX_FMT_H264, .max_width = H264_MAX_SIZE_W, .max_height = H264_MAX_SIZE_H, .open = hva_h264_open, .close = hva_h264_close, .encode = hva_h264_encode, }; const struct hva_enc nv21h264enc = { .name = "H264(NV21)", .pixelformat = V4L2_PIX_FMT_NV21, .streamformat = V4L2_PIX_FMT_H264, .max_width = H264_MAX_SIZE_W, .max_height = H264_MAX_SIZE_H, .open = hva_h264_open, .close = hva_h264_close, .encode = hva_h264_encode, };

Overall Contributors

PersonTokensPropCommitsCommitProp
Jean-Christophe Trotin3895100.00%2100.00%
Total3895100.00%2100.00%
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.