From: ming_qian Date: Tue, 22 Oct 2019 06:21:26 +0000 (+0800) Subject: MLK-22822:VPU Encoder: check the stream buffer free space before encode X-Git-Tag: rel_imx_4.19.35_1.1.0~11 X-Git-Url: https://git.somdevices.com/?a=commitdiff_plain;h=0f7c65e0bcbb938a6c9c806e3827b176eccd02e7;p=linux.git MLK-22822:VPU Encoder: check the stream buffer free space before encode frame If the free space of stream buffer is not enough for one frame, vpu may overwrite the data or hang. so check before encode frame can avoid it. Add new ctrl V4L2_CID_MPEG_VIDEO_H264_CPB_SIZE, user can use this ctrl to set the coded picture buffer size. Signed-off-by: ming_qian Reviewed-by: Shijie Qin (cherry picked from commit 1af0b35c6bfffa57e27f0a39c8b040b93d973278) --- diff --git a/drivers/mxc/vpu_malone/vpu_b0.h b/drivers/mxc/vpu_malone/vpu_b0.h index 0288dd0f6662..255247579403 100644 --- a/drivers/mxc/vpu_malone/vpu_b0.h +++ b/drivers/mxc/vpu_malone/vpu_b0.h @@ -3,12 +3,12 @@ */ /* - * The code contained herein is licensed under the GNU Lesser General - * Public License. You may obtain a copy of the GNU Lesser General - * Public License Version 2.1 or later at the following locations: + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: * - * http://www.opensource.org/licenses/lgpl-license.html - * http://www.gnu.org/copyleft/lgpl.html + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html */ /*! @@ -452,12 +452,12 @@ struct vpu_ctx { #define LVL_BIT_FLOW (1 << 13) #define LVL_BIT_FRAME_COUNT (1 << 14) -#define vpu_err(fmt, arg...) pr_info("[VPU Decoder]\t " fmt, ## arg) +#define vpu_err(fmt, arg...) pr_info("[VPU Decoder] " fmt, ## arg) #define vpu_dbg(level, fmt, arg...) \ do { \ if (vpu_dbg_level_decoder & (level)) \ - pr_info("[VPU Decoder]\t " fmt, ## arg); \ + pr_info("[VPU Decoder] " fmt, ## arg); \ } while (0) #define V4L2_NXP_BUF_FLAG_CODECCONFIG 0x00200000 diff --git a/drivers/mxc/vpu_malone/vpu_debug_log.h b/drivers/mxc/vpu_malone/vpu_debug_log.h index e6f8346de834..df1385ba7588 100644 --- a/drivers/mxc/vpu_malone/vpu_debug_log.h +++ b/drivers/mxc/vpu_malone/vpu_debug_log.h @@ -3,12 +3,12 @@ */ /* - * The code contained herein is licensed under the GNU Lesser General - * Public License. You may obtain a copy of the GNU Lesser General - * Public License Version 2.1 or later at the following locations: + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: * - * http://www.opensource.org/licenses/lgpl-license.html - * http://www.gnu.org/copyleft/lgpl.html + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html */ /*! diff --git a/drivers/mxc/vpu_malone/vpu_ts.h b/drivers/mxc/vpu_malone/vpu_ts.h index 1d8e632dc1ed..e51e4d62ecfd 100644 --- a/drivers/mxc/vpu_malone/vpu_ts.h +++ b/drivers/mxc/vpu_malone/vpu_ts.h @@ -3,12 +3,12 @@ */ /* - * The code contained herein is licensed under the GNU Lesser General - * Public License. You may obtain a copy of the GNU Lesser General - * Public License Version 2.1 or later at the following locations: + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: * - * http://www.opensource.org/licenses/lgpl-license.html - * http://www.gnu.org/copyleft/lgpl.html + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html */ /* diff --git a/drivers/mxc/vpu_windsor/vpu_encoder_b0.c b/drivers/mxc/vpu_windsor/vpu_encoder_b0.c index dca615b6a06b..1efa1fc6cc61 100644 --- a/drivers/mxc/vpu_windsor/vpu_encoder_b0.c +++ b/drivers/mxc/vpu_windsor/vpu_encoder_b0.c @@ -125,6 +125,7 @@ static int inc_frame(struct queue_data *queue); static void dec_frame(struct vpu_frame_info *frame); static int submit_input_and_encode(struct vpu_ctx *ctx); static int process_stream_output(struct vpu_ctx *ctx); +static u32 get_ptr(u32 ptr); static char *get_event_str(u32 event) { @@ -1859,6 +1860,14 @@ static struct vb2_data_req *find_vb2_data_by_sequence(struct queue_data *queue, return NULL; } +static void update_stream_desc_rptr(struct vpu_ctx *ctx, u32 rptr) +{ + pBUFFER_DESCRIPTOR_TYPE stream_buffer_desc; + + stream_buffer_desc = get_rpc_stream_buffer_desc(ctx); + stream_buffer_desc->rptr = rptr; +} + static int do_configure_codec(struct vpu_ctx *ctx) { pBUFFER_DESCRIPTOR_TYPE pEncStrBuffDesc = NULL; @@ -2160,6 +2169,31 @@ static void clear_queue_rw_flag(struct queue_data *queue, int flag) clear_bit(flag, &queue->rw_flag); } +u32 get_free_space(struct vpu_ctx *ctx) +{ + pBUFFER_DESCRIPTOR_TYPE desc = get_rpc_stream_buffer_desc(ctx); + u32 start = get_ptr(desc->start); + u32 end = get_ptr(desc->end); + u32 wptr = get_ptr(desc->wptr); + u32 rptr = get_ptr(desc->rptr); + + if (rptr > wptr) + return (rptr - wptr); + else if (rptr < wptr) + return (end - start + rptr - wptr); + else + return (end - start); + +} + +bool check_stream_buffer_for_coded_picture(struct vpu_ctx *ctx) +{ + if (get_free_space(ctx) < ctx->cpb_size) + return false; + + return true; +} + static int submit_input_and_encode(struct vpu_ctx *ctx) { struct queue_data *queue; @@ -2177,6 +2211,9 @@ static int submit_input_and_encode(struct vpu_ctx *ctx) if (list_empty(&queue->drv_q)) goto exit; + if (!check_stream_buffer_for_coded_picture(ctx)) + goto exit; + if (test_bit(VPU_ENC_STATUS_STOP_SEND, &ctx->status)) goto exit; if (!test_bit(VPU_ENC_STATUS_START_DONE, &ctx->status)) @@ -2538,7 +2575,7 @@ static bool process_frame_done(struct queue_data *queue) frame->rptr = get_ptr(stream_buffer_desc->rptr); if (precheck_frame(ctx, frame)) { - stream_buffer_desc->rptr = frame->rptr; + update_stream_desc_rptr(ctx, frame->rptr); put_frame_idle(frame); frame = NULL; return true; @@ -2554,7 +2591,7 @@ static bool process_frame_done(struct queue_data *queue) else transfer_stream_output(ctx, frame, p_data_req); - stream_buffer_desc->rptr = frame->rptr; + update_stream_desc_rptr(ctx, frame->rptr); if (!frame->eos) { fill_vb_sequence(p_data_req->vb2_buf, frame->info.uFrameID); p_data_req->vb2_buf->timestamp = frame->timestamp; @@ -2590,6 +2627,8 @@ static int process_stream_output(struct vpu_ctx *ctx) } up(&queue->drv_q_lock); + submit_input_and_encode(ctx); + return 0; } @@ -2658,6 +2697,33 @@ static int handle_event_mem_request(struct vpu_ctx *ctx, return 0; } +static bool check_stream_buffer_desc(struct vpu_ctx *ctx, + pBUFFER_DESCRIPTOR_TYPE stream_buffer_desc) +{ + u32 start; + u32 end; + u32 rptr; + u32 wptr; + + if (!stream_buffer_desc) + return false; + start = get_ptr(stream_buffer_desc->start); + end = get_ptr(stream_buffer_desc->end); + rptr = get_ptr(stream_buffer_desc->rptr); + wptr = get_ptr(stream_buffer_desc->wptr); + + if (rptr < start || rptr > end || + wptr < start || wptr > end || + end <= start || + end - start != ctx->encoder_stream.size) { + vpu_err("stream buffer desc is invalid, s:%x,e:%x,r:%x,w:%x\n", + start, end, rptr, wptr); + return false; + } + + return true; +} + static int handle_event_frame_done(struct vpu_ctx *ctx, MEDIAIP_ENC_PIC_INFO *pEncPicInfo) { @@ -2679,19 +2745,8 @@ static int handle_event_frame_done(struct vpu_ctx *ctx, } stream_buffer_desc = get_rpc_stream_buffer_desc(ctx); - if (stream_buffer_desc->rptr < stream_buffer_desc->start || - stream_buffer_desc->rptr > stream_buffer_desc->end || - stream_buffer_desc->wptr < stream_buffer_desc->start || - stream_buffer_desc->wptr > stream_buffer_desc->end || - stream_buffer_desc->end - stream_buffer_desc->start != - ctx->encoder_stream.size) { - vpu_err("stream buffer desc is invalid, s:%x,e:%x,r:%x,w:%x\n", - stream_buffer_desc->start, - stream_buffer_desc->end, - stream_buffer_desc->rptr, - stream_buffer_desc->wptr); + if (!check_stream_buffer_desc(ctx, stream_buffer_desc)) return -EINVAL; - } show_enc_pic_info(pEncPicInfo); record_start_time(ctx, V4L2_DST); @@ -3972,6 +4027,28 @@ static int show_instance_status(struct vpu_ctx *ctx, char *buf, u32 size) return num; } +static int show_instance_stream_buffer_desc(struct vpu_ctx *ctx, + char *buf, u32 size) +{ + pBUFFER_DESCRIPTOR_TYPE stream_buffer_desc; + int num = 0; + + stream_buffer_desc = get_rpc_stream_buffer_desc(ctx); + num += scnprintf(buf + num, size - num, + "\t%-13s:0x%x\n", "start", + get_ptr(stream_buffer_desc->start)); + num += scnprintf(buf + num, size - num, + "\t%-13s:0x%x\n", "end", + get_ptr(stream_buffer_desc->end)); + num += scnprintf(buf + num, size - num, + "\t%-13s:0x%x\n", "rptr", + get_ptr(stream_buffer_desc->rptr)); + num += scnprintf(buf + num, size - num, + "\t%-13s:0x%x\n", "wptr", + get_ptr(stream_buffer_desc->wptr)); + return num; +} + static int show_instance_others(struct vpu_attr *attr, char *buf, u32 size) { int num = 0; @@ -4044,6 +4121,9 @@ static ssize_t show_instance_info(struct device *dev, if (ctx) { num += show_v4l2_buf_status(ctx, buf + num, PAGE_SIZE - num); num += show_instance_status(ctx, buf + num, PAGE_SIZE - num); + num += show_instance_stream_buffer_desc(ctx, + buf + num, + PAGE_SIZE - num); } mutex_unlock(&vpudev->dev_mutex); diff --git a/drivers/mxc/vpu_windsor/vpu_encoder_b0.h b/drivers/mxc/vpu_windsor/vpu_encoder_b0.h index 1661108845bf..a9ad783461b1 100644 --- a/drivers/mxc/vpu_windsor/vpu_encoder_b0.h +++ b/drivers/mxc/vpu_windsor/vpu_encoder_b0.h @@ -71,6 +71,8 @@ extern unsigned int vpu_dbg_level_encoder; #define QP_MAX 51 #define QP_MIN 0 #define QP_DEFAULT 25 +#define CPB_CTRL_UNIT 1024 +#define CPB_COUNT 3 #define VPU_DISABLE_BITS 0x7 #define VPU_ENCODER_MASK 0x1 @@ -420,6 +422,7 @@ struct vpu_ctx { unsigned int frozen_count; u_int32 sequence; s64 timestams[VPU_ENC_SEQ_CAPACITY]; + u32 cpb_size; }; #define LVL_ERR (1 << 0) @@ -439,7 +442,7 @@ struct vpu_ctx { #define LVL_FUNC (1 << 16) #ifndef TAG -#define TAG "[VPU Encoder]\t " +#define TAG "[VPU Encoder] " #endif #define vpu_dbg(level, fmt, arg...) \ diff --git a/drivers/mxc/vpu_windsor/vpu_encoder_ctrl.c b/drivers/mxc/vpu_windsor/vpu_encoder_ctrl.c index 0bf373cb08e5..bd43587c5c2a 100644 --- a/drivers/mxc/vpu_windsor/vpu_encoder_ctrl.c +++ b/drivers/mxc/vpu_windsor/vpu_encoder_ctrl.c @@ -255,6 +255,15 @@ static int set_force_key_frame(struct v4l2_ctrl *ctrl) return 0; } +static int set_h264_cpb_size(struct v4l2_ctrl *ctrl) +{ + struct vpu_ctx *ctx = v4l2_ctrl_to_ctx(ctrl); + + ctx->cpb_size = ctrl->val * CPB_CTRL_UNIT; + + return 0; +} + static int add_ctrl_h264_profile(struct vpu_ctx *ctx) { static const struct v4l2_ctrl_ops ctrl_h264_profile_ops = { @@ -566,6 +575,26 @@ static int add_ctrl_force_key_frame(struct vpu_ctx *ctx) return 0; } +static int add_ctrl_h264_cpb_size(struct vpu_ctx *ctx) +{ + static const struct v4l2_ctrl_ops ctrl_cpb_size_ops = { + .s_ctrl = set_h264_cpb_size, + }; + struct v4l2_ctrl *ctrl; + + ctrl = v4l2_ctrl_new_std(&ctx->ctrl_handler, + &ctrl_cpb_size_ops, + V4L2_CID_MPEG_VIDEO_H264_CPB_SIZE, + 64, 10240, 1, 1024); + + if (!ctrl) { + vpu_err("add ctrl h264 cpb size fail\n"); + return -EINVAL; + } + + return 0; +} + static int vpu_enc_register_ctrls(struct vpu_ctx *ctx) { add_ctrl_h264_profile(ctx); @@ -582,6 +611,7 @@ static int vpu_enc_register_ctrls(struct vpu_ctx *ctx) add_ctrl_min_buffers_for_output(ctx); add_ctrl_display_re_ordering(ctx); add_ctrl_force_key_frame(ctx); + add_ctrl_h264_cpb_size(ctx); return 0; } diff --git a/drivers/mxc/vpu_windsor/vpu_encoder_mem.c b/drivers/mxc/vpu_windsor/vpu_encoder_mem.c index 56724a2d0784..ac9dddd4915c 100644 --- a/drivers/mxc/vpu_windsor/vpu_encoder_mem.c +++ b/drivers/mxc/vpu_windsor/vpu_encoder_mem.c @@ -603,7 +603,8 @@ int vpu_enc_alloc_stream(struct vpu_ctx *ctx) if (ctx->encoder_stream.virt_addr) return 0; - ctx->encoder_stream.size = STREAM_SIZE; + ctx->encoder_stream.size = + max_t(u32, ctx->cpb_size * CPB_COUNT, STREAM_SIZE); ret = vpu_enc_alloc_dma_buffer(ctx, &ctx->encoder_stream); if (ret) { vpu_err("alloc encoder stream buffer fail\n");