diff options
Diffstat (limited to 'drivers/staging/media/sunxi/cedrus/cedrus_video.c')
-rw-r--r-- | drivers/staging/media/sunxi/cedrus/cedrus_video.c | 102 |
1 files changed, 49 insertions, 53 deletions
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_video.c b/drivers/staging/media/sunxi/cedrus/cedrus_video.c index eeee3efd247b..15cf1f10221b 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_video.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus_video.c @@ -29,8 +29,8 @@ #define CEDRUS_MIN_WIDTH 16U #define CEDRUS_MIN_HEIGHT 16U -#define CEDRUS_MAX_WIDTH 3840U -#define CEDRUS_MAX_HEIGHT 2160U +#define CEDRUS_MAX_WIDTH 4096U +#define CEDRUS_MAX_HEIGHT 2304U static struct cedrus_format cedrus_formats[] = { { @@ -42,6 +42,11 @@ static struct cedrus_format cedrus_formats[] = { .directions = CEDRUS_DECODE_SRC, }, { + .pixelformat = V4L2_PIX_FMT_HEVC_SLICE, + .directions = CEDRUS_DECODE_SRC, + .capabilities = CEDRUS_CAPABILITY_H265_DEC, + }, + { .pixelformat = V4L2_PIX_FMT_SUNXI_TILED_NV12, .directions = CEDRUS_DECODE_DST, }, @@ -62,34 +67,31 @@ static inline struct cedrus_ctx *cedrus_file2ctx(struct file *file) static struct cedrus_format *cedrus_find_format(u32 pixelformat, u32 directions, unsigned int capabilities) { + struct cedrus_format *first_valid_fmt = NULL; struct cedrus_format *fmt; unsigned int i; for (i = 0; i < CEDRUS_FORMATS_COUNT; i++) { fmt = &cedrus_formats[i]; - if (fmt->capabilities && (fmt->capabilities & capabilities) != - fmt->capabilities) + if ((fmt->capabilities & capabilities) != fmt->capabilities || + !(fmt->directions & directions)) continue; - if (fmt->pixelformat == pixelformat && - (fmt->directions & directions) != 0) + if (fmt->pixelformat == pixelformat) break; + + if (!first_valid_fmt) + first_valid_fmt = fmt; } if (i == CEDRUS_FORMATS_COUNT) - return NULL; + return first_valid_fmt; return &cedrus_formats[i]; } -static bool cedrus_check_format(u32 pixelformat, u32 directions, - unsigned int capabilities) -{ - return cedrus_find_format(pixelformat, directions, capabilities); -} - -static void cedrus_prepare_format(struct v4l2_pix_format *pix_fmt) +void cedrus_prepare_format(struct v4l2_pix_format *pix_fmt) { unsigned int width = pix_fmt->width; unsigned int height = pix_fmt->height; @@ -105,9 +107,11 @@ static void cedrus_prepare_format(struct v4l2_pix_format *pix_fmt) switch (pix_fmt->pixelformat) { case V4L2_PIX_FMT_MPEG2_SLICE: case V4L2_PIX_FMT_H264_SLICE: + case V4L2_PIX_FMT_HEVC_SLICE: /* Zero bytes per line for encoded source. */ bytesperline = 0; - + /* Choose some minimum size since this can't be 0 */ + sizeimage = max_t(u32, SZ_1K, sizeimage); break; case V4L2_PIX_FMT_SUNXI_TILED_NV12: @@ -214,16 +218,7 @@ static int cedrus_g_fmt_vid_cap(struct file *file, void *priv, { struct cedrus_ctx *ctx = cedrus_file2ctx(file); - /* Fall back to dummy default by lack of hardware configuration. */ - if (!ctx->dst_fmt.width || !ctx->dst_fmt.height) { - f->fmt.pix.pixelformat = V4L2_PIX_FMT_SUNXI_TILED_NV12; - cedrus_prepare_format(&f->fmt.pix); - - return 0; - } - f->fmt.pix = ctx->dst_fmt; - return 0; } @@ -232,17 +227,7 @@ static int cedrus_g_fmt_vid_out(struct file *file, void *priv, { struct cedrus_ctx *ctx = cedrus_file2ctx(file); - /* Fall back to dummy default by lack of hardware configuration. */ - if (!ctx->dst_fmt.width || !ctx->dst_fmt.height) { - f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG2_SLICE; - f->fmt.pix.sizeimage = SZ_1K; - cedrus_prepare_format(&f->fmt.pix); - - return 0; - } - f->fmt.pix = ctx->src_fmt; - return 0; } @@ -252,11 +237,14 @@ static int cedrus_try_fmt_vid_cap(struct file *file, void *priv, struct cedrus_ctx *ctx = cedrus_file2ctx(file); struct cedrus_dev *dev = ctx->dev; struct v4l2_pix_format *pix_fmt = &f->fmt.pix; + struct cedrus_format *fmt = + cedrus_find_format(pix_fmt->pixelformat, CEDRUS_DECODE_DST, + dev->capabilities); - if (!cedrus_check_format(pix_fmt->pixelformat, CEDRUS_DECODE_DST, - dev->capabilities)) + if (!fmt) return -EINVAL; + pix_fmt->pixelformat = fmt->pixelformat; cedrus_prepare_format(pix_fmt); return 0; @@ -268,15 +256,14 @@ static int cedrus_try_fmt_vid_out(struct file *file, void *priv, struct cedrus_ctx *ctx = cedrus_file2ctx(file); struct cedrus_dev *dev = ctx->dev; struct v4l2_pix_format *pix_fmt = &f->fmt.pix; + struct cedrus_format *fmt = + cedrus_find_format(pix_fmt->pixelformat, CEDRUS_DECODE_SRC, + dev->capabilities); - if (!cedrus_check_format(pix_fmt->pixelformat, CEDRUS_DECODE_SRC, - dev->capabilities)) - return -EINVAL; - - /* Source image size has to be provided by userspace. */ - if (pix_fmt->sizeimage == 0) + if (!fmt) return -EINVAL; + pix_fmt->pixelformat = fmt->pixelformat; cedrus_prepare_format(pix_fmt); return 0; @@ -322,6 +309,17 @@ static int cedrus_s_fmt_vid_out(struct file *file, void *priv, ctx->src_fmt = f->fmt.pix; + switch (ctx->src_fmt.pixelformat) { + case V4L2_PIX_FMT_H264_SLICE: + vq->subsystem_flags |= + VB2_V4L2_FL_SUPPORTS_M2M_HOLD_CAPTURE_BUF; + break; + default: + vq->subsystem_flags &= + ~VB2_V4L2_FL_SUPPORTS_M2M_HOLD_CAPTURE_BUF; + break; + } + /* Propagate colorspace information to capture. */ ctx->dst_fmt.colorspace = f->fmt.pix.colorspace; ctx->dst_fmt.xfer_func = f->fmt.pix.xfer_func; @@ -355,6 +353,9 @@ const struct v4l2_ioctl_ops cedrus_ioctl_ops = { .vidioc_streamon = v4l2_m2m_ioctl_streamon, .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, + .vidioc_try_decoder_cmd = v4l2_m2m_ioctl_stateless_try_decoder_cmd, + .vidioc_decoder_cmd = v4l2_m2m_ioctl_stateless_decoder_cmd, + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, .vidioc_unsubscribe_event = v4l2_event_unsubscribe, }; @@ -364,21 +365,12 @@ static int cedrus_queue_setup(struct vb2_queue *vq, unsigned int *nbufs, struct device *alloc_devs[]) { struct cedrus_ctx *ctx = vb2_get_drv_priv(vq); - struct cedrus_dev *dev = ctx->dev; struct v4l2_pix_format *pix_fmt; - u32 directions; - if (V4L2_TYPE_IS_OUTPUT(vq->type)) { - directions = CEDRUS_DECODE_SRC; + if (V4L2_TYPE_IS_OUTPUT(vq->type)) pix_fmt = &ctx->src_fmt; - } else { - directions = CEDRUS_DECODE_DST; + else pix_fmt = &ctx->dst_fmt; - } - - if (!cedrus_check_format(pix_fmt->pixelformat, directions, - dev->capabilities)) - return -EINVAL; if (*nplanes) { if (sizes[0] < pix_fmt->sizeimage) @@ -453,6 +445,10 @@ static int cedrus_start_streaming(struct vb2_queue *vq, unsigned int count) ctx->current_codec = CEDRUS_CODEC_H264; break; + case V4L2_PIX_FMT_HEVC_SLICE: + ctx->current_codec = CEDRUS_CODEC_H265; + break; + default: return -EINVAL; } |