MLK-22822:VPU Encoder: check the stream buffer free space before encode
authorming_qian <ming.qian@nxp.com>
Tue, 22 Oct 2019 06:21:26 +0000 (14:21 +0800)
committerShijie Qin <shijie.qin@nxp.com>
Thu, 24 Oct 2019 10:58:36 +0000 (18:58 +0800)
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 <ming.qian@nxp.com>
Reviewed-by: Shijie Qin <shijie.qin@nxp.com>
(cherry picked from commit 1af0b35c6bfffa57e27f0a39c8b040b93d973278)

drivers/mxc/vpu_malone/vpu_b0.h
drivers/mxc/vpu_malone/vpu_debug_log.h
drivers/mxc/vpu_malone/vpu_ts.h
drivers/mxc/vpu_windsor/vpu_encoder_b0.c
drivers/mxc/vpu_windsor/vpu_encoder_b0.h
drivers/mxc/vpu_windsor/vpu_encoder_ctrl.c
drivers/mxc/vpu_windsor/vpu_encoder_mem.c

index 0288dd0..2552475 100644 (file)
@@ -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
index e6f8346..df1385b 100644 (file)
@@ -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
  */
 
 /*!
index 1d8e632..e51e4d6 100644 (file)
@@ -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
  */
 
 /*
index dca615b..1efa1fc 100644 (file)
@@ -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);
 
index 1661108..a9ad783 100644 (file)
@@ -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...) \
index 0bf373c..bd43587 100644 (file)
@@ -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;
 }
index 56724a2..ac9dddd 100644 (file)
@@ -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");