diff --git a/libv4l-rockchip_v2/libv4l-encplugin-rockchip.c b/libv4l-rockchip_v2/libv4l-encplugin-rockchip.c index 28ababa1d1ac1e80b8e8880b3373c36fcad2fe09..46800e54232d8f72320cf7255fbb449c95ec2098 100644 --- a/libv4l-rockchip_v2/libv4l-encplugin-rockchip.c +++ b/libv4l-rockchip_v2/libv4l-encplugin-rockchip.c @@ -47,6 +47,7 @@ #define DEFAULT_FRAME_RATE 30 #define DEFAULT_BITRATE 1000000 #define PENDING_BUFFER_QUEUE_SIZE VIDEO_MAX_FRAME +#define round_down(x, y) ((x) - ((x) % (y))) /* * struct pending_buffer - A v4l2 buffer pending for QBUF. @@ -100,6 +101,17 @@ struct pending_buffer_queue { * @flushing: Indicate the encoder is flushing frame. * @eos_buffer: The last buffer to be flushed. Reset to NULL after the buffer * is enqueued to the driver. + * @output_format: The compressed format of the encoded video. + * @frame_width: The width of the input frame. + * @frame_height: The height of the input frame. + * @crop_width: The width of the cropped rectangle. The value is set when + * VIDIOC_S_FMT or VIDIOC_S_CROP for OUTPUT queue is called + * successfully, and is used as the width of encoded video. + * Note: we store the original value passed from ioctl, instead of + * the value adjusted by the driver. Also, the value should be + * smaller or equal than frame_width. + * @crop_height: The height of the croped rectangle. Other description is + * the same as crop_width. */ struct encoder_context { void *enc; @@ -115,6 +127,11 @@ struct encoder_context { struct v4l2_ext_control v4l2_ctrls[MAX_NUM_GET_CONFIG_CTRLS]; bool flushing; struct pending_buffer *eos_buffer; + uint32_t output_format; + uint32_t frame_width; + uint32_t frame_height; + uint32_t crop_width; + uint32_t crop_height; }; static void *plugin_init(int fd); @@ -135,6 +152,12 @@ static int ioctl_s_ext_ctrls_locked(struct encoder_context *ctx, int fd, struct v4l2_ext_controls *ext_ctrls); static int ioctl_s_parm_locked(struct encoder_context *ctx, int fd, struct v4l2_streamparm *parms); +static int ioctl_s_fmt_locked(struct encoder_context *ctx, int fd, + struct v4l2_format *format); +static int ioctl_s_crop_locked(struct encoder_context *ctx, int fd, + struct v4l2_crop *crop); +static int ioctl_g_crop_locked(struct encoder_context *ctx, int fd, + struct v4l2_crop *crop); static int ioctl_reqbufs_locked(struct encoder_context *ctx, int fd, struct v4l2_requestbuffers *reqbufs); static int ioctl_encoder_cmd_locked(struct encoder_context *ctx, int fd, @@ -270,6 +293,18 @@ static int plugin_ioctl(void *dev_ops_priv, int fd, ret = ioctl_s_parm_locked(ctx, fd, arg); break; + case VIDIOC_S_FMT: + ret = ioctl_s_fmt_locked(ctx, fd, arg); + break; + + case VIDIOC_S_CROP: + ret = ioctl_s_crop_locked(ctx, fd, arg); + break; + + case VIDIOC_G_CROP: + ret = ioctl_g_crop_locked(ctx, fd, arg); + break; + case VIDIOC_REQBUFS: ret = ioctl_reqbufs_locked(ctx, fd, arg); break; @@ -498,6 +533,76 @@ static int ioctl_s_parm_locked(struct encoder_context *ctx, int fd, return SYS_IOCTL(fd, VIDIOC_S_PARM, parms); } +static int ioctl_s_fmt_locked(struct encoder_context *ctx, int fd, + struct v4l2_format *format) +{ + uint32_t width = format->fmt.pix_mp.width; + uint32_t height = format->fmt.pix_mp.height; + int ret = SYS_IOCTL(fd, VIDIOC_S_FMT, format); + if (ret) + return ret; + if (!V4L2_TYPE_IS_OUTPUT(format->type)) { + ctx->output_format = format->fmt.pix_mp.pixelformat; + return 0; + } + + /* The width and height of H264 video should be even. */ + if (ctx->output_format == V4L2_PIX_FMT_H264) { + width = round_down(width, 2); + height = round_down(height, 2); + } + ctx->frame_width = width; + ctx->frame_height = height; + ctx->crop_width = width; + ctx->crop_height = height; + return 0; +} + +static int ioctl_s_crop_locked(struct encoder_context *ctx, int fd, + struct v4l2_crop *crop) +{ + /* + * We do not support offsets, and the crop size should not be + * bigger than the frame size. In this case, we reset the crop + * size to full frame size. + */ + if (crop->c.left != 0 || crop->c.top != 0 || + crop->c.width > ctx->frame_width || + crop->c.height > ctx->frame_height) { + crop->c.left = 0; + crop->c.top = 0; + crop->c.width = ctx->frame_width; + crop->c.height = ctx->frame_height; + } + + uint32_t width = crop->c.width; + uint32_t height = crop->c.height; + int ret = SYS_IOCTL(fd, VIDIOC_S_CROP, crop); + if (ret || !V4L2_TYPE_IS_OUTPUT(crop->type)) + return ret; + + /* The width and height of H264 video should be even. */ + if (ctx->output_format == V4L2_PIX_FMT_H264) { + width = round_down(width, 2); + height = round_down(height, 2); + } + ctx->crop_width = width; + ctx->crop_height = height; + return 0; +} + +static int ioctl_g_crop_locked(struct encoder_context *ctx, int fd, + struct v4l2_crop *crop) +{ + int ret = SYS_IOCTL(fd, VIDIOC_G_CROP, crop); + if (ret || !V4L2_TYPE_IS_OUTPUT(crop->type)) + return ret; + + crop->c.width = ctx->crop_width; + crop->c.height = ctx->crop_height; + return 0; +} + static int ioctl_reqbufs_locked(struct encoder_context *ctx, int fd, struct v4l2_requestbuffers *reqbufs) { @@ -623,14 +728,8 @@ static int initialize_libvpu(struct encoder_context *ctx, int fd) init_param.output_format = format.fmt.pix_mp.pixelformat; /* Get the cropped size. */ - struct v4l2_crop crop; - memset(&crop, 0, sizeof(crop)); - crop.type = ctx->output_streamon_type; - ret = SYS_IOCTL(fd, VIDIOC_G_CROP, &crop); - if (ret) - return ret; - init_param.width = crop.c.width; - init_param.height = crop.c.height; + init_param.width = ctx->crop_width; + init_param.height = ctx->crop_height; init_param.h264e = ctx->init_param.h264e;