From patchwork Wed Dec 19 12:18:53 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dafna Hirschfeld X-Patchwork-Id: 10737173 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id AA2D514E2 for ; Wed, 19 Dec 2018 12:19:45 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 8AF9A2A8AE for ; Wed, 19 Dec 2018 12:19:45 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 7BB082A8A7; Wed, 19 Dec 2018 12:19:45 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FROM,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 58C2F2A8A7 for ; Wed, 19 Dec 2018 12:19:43 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728778AbeLSMTm (ORCPT ); Wed, 19 Dec 2018 07:19:42 -0500 Received: from mail-wr1-f67.google.com ([209.85.221.67]:40331 "EHLO mail-wr1-f67.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727993AbeLSMTm (ORCPT ); Wed, 19 Dec 2018 07:19:42 -0500 Received: by mail-wr1-f67.google.com with SMTP id p4so19301060wrt.7 for ; Wed, 19 Dec 2018 04:19:39 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id; bh=5QFeWakKpj7tR3iay62XZTQPK5ya1GNek1eiWsqNNow=; b=DN7pMmcZPrMH2YHxvu1GAF7SV5hp7v1oZ5UNUexlhV6PYkoLf2Rj/3sr+ANeAVaVR1 ZDquUuEKsQHyOxcX4Aytd/zaxWIaU8em1LHjWuQweZw0kg2phAQipKjG39M/38uRYiDB lDjL7lIicGv4wvOwV+B2NsSbmFbjIrdZXc/I0XfJgzZ/vKDxlrgILLYMtzMeK0xC7n4j /uV4qHau1PYZ3vK7x6Y5vY5zGFERiv17Vd+jhOz29cBxKEtCs6eT1V2oX9spDkKn7nqC DHFae+5peYgJ69fd4WChhf24GxQMt3m6o4ZoTsNmHohFkxEFEwm0RCuG9Cw7B21w/8r3 UtNw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id; bh=5QFeWakKpj7tR3iay62XZTQPK5ya1GNek1eiWsqNNow=; b=cZKOYMUzN697tpQHUHjnZFTXItrDk8xgftTFJLdwQa7i/3r+lnrsbL5L5YP5Hgkech iJ2lH5/hGdcqE0QXzto0fypsF7awvQPSX411bkoax0mZ8oufk090lQzgDQ1Lbq/Ky7VV doLhiPKuJKqgyGYBtH9M9p1GxvKtyXSVO48S/z5Zf0XcW42mY4rY0rzryLijSikGncZU uWcinnALEKAGm67CNPQ5UZmRPhCFZGXGPLFs71WaMDwrUwFua4dozS2Hrn6AwlnKFchB kk5zGHIam7WcotgP8poLnE+tniB9lDj7Z7bhEW3rdpr75/XbxuO2XwABHoUgm04CQP/5 NaLw== X-Gm-Message-State: AA+aEWbYOLaUMkpPjtFUzlvw+XWQ2u+n4+cocvtFox7nUbtfvCvyAbx5 ag6I3N5K5irutDAUZdotGC/QflnWfs4= X-Google-Smtp-Source: AFSGD/VAa4mvLSBRcprMXzmFEuiloUIM4SqSxs3X062g6c3C0zaUza+2DwpjX6An1M7IGTIIfD8R4w== X-Received: by 2002:adf:9484:: with SMTP id 4mr17054738wrr.98.1545221978218; Wed, 19 Dec 2018 04:19:38 -0800 (PST) Received: from localhost.localdomain ([87.71.129.70]) by smtp.gmail.com with ESMTPSA id l6sm6854665wrv.70.2018.12.19.04.19.36 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 19 Dec 2018 04:19:37 -0800 (PST) From: Dafna Hirschfeld To: linux-media@vger.kernel.org Cc: hverkuil@xs4all.nl, helen.koike@collabora.com, Dafna Hirschfeld Subject: [PATCH v2] media: vicodec: add support for CROP selection in the encoder Date: Wed, 19 Dec 2018 04:18:53 -0800 Message-Id: <20181219121853.122797-1-dafna3@gmail.com> X-Mailer: git-send-email 2.17.1 Sender: linux-media-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Add support for the selection api for the crop target in the encoder. The driver rounds up the coded width and height such that all planes dimensions are multiple of 8. Signed-off-by: Dafna Hirschfeld --- Changes from v1: Renaming fields to be more descriptive. Setting default values to g_selection for compose and ignoring s_selection for compose. Some cleanups. drivers/media/platform/vicodec/codec-fwht.c | 50 ++-- drivers/media/platform/vicodec/codec-fwht.h | 9 +- .../media/platform/vicodec/codec-v4l2-fwht.c | 28 ++- .../media/platform/vicodec/codec-v4l2-fwht.h | 6 +- drivers/media/platform/vicodec/vicodec-core.c | 237 ++++++++++++++---- 5 files changed, 241 insertions(+), 89 deletions(-) diff --git a/drivers/media/platform/vicodec/codec-fwht.c b/drivers/media/platform/vicodec/codec-fwht.c index a6fd0477633b..a862442a500f 100644 --- a/drivers/media/platform/vicodec/codec-fwht.c +++ b/drivers/media/platform/vicodec/codec-fwht.c @@ -11,6 +11,7 @@ #include #include "codec-fwht.h" +#include /* * Note: bit 0 of the header must always be 0. Otherwise it cannot @@ -659,7 +660,7 @@ static void add_deltas(s16 *deltas, const u8 *ref, int stride) } static u32 encode_plane(u8 *input, u8 *refp, __be16 **rlco, __be16 *rlco_max, - struct fwht_cframe *cf, u32 height, u32 width, + struct fwht_cframe *cf, u32 height, u32 width, u32 stride, unsigned int input_step, bool is_intra, bool next_is_intra) { @@ -671,7 +672,11 @@ static u32 encode_plane(u8 *input, u8 *refp, __be16 **rlco, __be16 *rlco_max, unsigned int last_size = 0; unsigned int i, j; + width = round_up(width, 8); + height = round_up(height, 8); + for (j = 0; j < height / 8; j++) { + input = input_start + j * 8 * stride * input_step; for (i = 0; i < width / 8; i++) { /* intra code, first frame is always intra coded. */ int blocktype = IBLOCK; @@ -679,9 +684,9 @@ static u32 encode_plane(u8 *input, u8 *refp, __be16 **rlco, __be16 *rlco_max, if (!is_intra) blocktype = decide_blocktype(input, refp, - deltablock, width, input_step); + deltablock, stride, input_step); if (blocktype == IBLOCK) { - fwht(input, cf->coeffs, width, input_step, 1); + fwht(input, cf->coeffs, stride, input_step, 1); quantize_intra(cf->coeffs, cf->de_coeffs, cf->i_frame_qp); } else { @@ -722,7 +727,6 @@ static u32 encode_plane(u8 *input, u8 *refp, __be16 **rlco, __be16 *rlco_max, } last_size = size; } - input += width * 7 * input_step; } exit_loop: @@ -756,7 +760,7 @@ u32 fwht_encode_frame(struct fwht_raw_frame *frm, rlco_max = rlco + size / 2 - 256; encoding = encode_plane(frm->luma, ref_frm->luma, &rlco, rlco_max, cf, - frm->height, frm->width, + frm->height, frm->width, frm->stride, frm->luma_alpha_step, is_intra, next_is_intra); if (encoding & FWHT_FRAME_UNENCODED) encoding |= FWHT_LUMA_UNENCODED; @@ -765,11 +769,12 @@ u32 fwht_encode_frame(struct fwht_raw_frame *frm, if (frm->components_num >= 3) { u32 chroma_h = frm->height / frm->height_div; u32 chroma_w = frm->width / frm->width_div; + u32 chroma_stride = frm->stride / frm->width_div; unsigned int chroma_size = chroma_h * chroma_w; rlco_max = rlco + chroma_size / 2 - 256; encoding |= encode_plane(frm->cb, ref_frm->cb, &rlco, rlco_max, - cf, chroma_h, chroma_w, + cf, chroma_h, chroma_w, chroma_stride, frm->chroma_step, is_intra, next_is_intra); if (encoding & FWHT_FRAME_UNENCODED) @@ -777,7 +782,7 @@ u32 fwht_encode_frame(struct fwht_raw_frame *frm, encoding &= ~FWHT_FRAME_UNENCODED; rlco_max = rlco + chroma_size / 2 - 256; encoding |= encode_plane(frm->cr, ref_frm->cr, &rlco, rlco_max, - cf, chroma_h, chroma_w, + cf, chroma_h, chroma_w, chroma_stride, frm->chroma_step, is_intra, next_is_intra); if (encoding & FWHT_FRAME_UNENCODED) @@ -789,7 +794,7 @@ u32 fwht_encode_frame(struct fwht_raw_frame *frm, rlco_max = rlco + size / 2 - 256; encoding |= encode_plane(frm->alpha, ref_frm->alpha, &rlco, rlco_max, cf, frm->height, frm->width, - frm->luma_alpha_step, + frm->stride, frm->luma_alpha_step, is_intra, next_is_intra); if (encoding & FWHT_FRAME_UNENCODED) encoding |= FWHT_ALPHA_UNENCODED; @@ -801,7 +806,7 @@ u32 fwht_encode_frame(struct fwht_raw_frame *frm, } static void decode_plane(struct fwht_cframe *cf, const __be16 **rlco, u8 *ref, - u32 height, u32 width, bool uncompressed) + u32 height, u32 width, u32 stride, bool uncompressed) { unsigned int copies = 0; s16 copy[8 * 8]; @@ -813,6 +818,8 @@ static void decode_plane(struct fwht_cframe *cf, const __be16 **rlco, u8 *ref, *rlco += width * height / 2; return; } + width = round_up(width, 8); + height = round_up(height, 8); /* * When decoding each macroblock the rlco pointer will be increased @@ -822,13 +829,13 @@ static void decode_plane(struct fwht_cframe *cf, const __be16 **rlco, u8 *ref, */ for (j = 0; j < height / 8; j++) { for (i = 0; i < width / 8; i++) { - u8 *refp = ref + j * 8 * width + i * 8; + u8 *refp = ref + j * 8 * stride + i * 8; if (copies) { memcpy(cf->de_fwht, copy, sizeof(copy)); if (stat & PFRAME_BIT) - add_deltas(cf->de_fwht, refp, width); - fill_decoder_block(refp, cf->de_fwht, width); + add_deltas(cf->de_fwht, refp, stride); + fill_decoder_block(refp, cf->de_fwht, stride); copies--; continue; } @@ -847,35 +854,38 @@ static void decode_plane(struct fwht_cframe *cf, const __be16 **rlco, u8 *ref, if (copies) memcpy(copy, cf->de_fwht, sizeof(copy)); if (stat & PFRAME_BIT) - add_deltas(cf->de_fwht, refp, width); - fill_decoder_block(refp, cf->de_fwht, width); + add_deltas(cf->de_fwht, refp, stride); + fill_decoder_block(refp, cf->de_fwht, stride); } } } void fwht_decode_frame(struct fwht_cframe *cf, struct fwht_raw_frame *ref, - u32 hdr_flags, unsigned int components_num) + u32 hdr_flags, unsigned int components_num, unsigned int stride) { const __be16 *rlco = cf->rlc_data; - decode_plane(cf, &rlco, ref->luma, cf->height, cf->width, + decode_plane(cf, &rlco, ref->luma, cf->height, cf->width, stride, hdr_flags & FWHT_FL_LUMA_IS_UNCOMPRESSED); if (components_num >= 3) { u32 h = cf->height; u32 w = cf->width; + u32 s = stride; if (!(hdr_flags & FWHT_FL_CHROMA_FULL_HEIGHT)) h /= 2; - if (!(hdr_flags & FWHT_FL_CHROMA_FULL_WIDTH)) + if (!(hdr_flags & FWHT_FL_CHROMA_FULL_WIDTH)) { w /= 2; - decode_plane(cf, &rlco, ref->cb, h, w, + s /= 2; + } + decode_plane(cf, &rlco, ref->cb, h, w, s, hdr_flags & FWHT_FL_CB_IS_UNCOMPRESSED); - decode_plane(cf, &rlco, ref->cr, h, w, + decode_plane(cf, &rlco, ref->cr, h, w, s, hdr_flags & FWHT_FL_CR_IS_UNCOMPRESSED); } if (components_num == 4) - decode_plane(cf, &rlco, ref->alpha, cf->height, cf->width, + decode_plane(cf, &rlco, ref->alpha, cf->height, cf->width, stride, hdr_flags & FWHT_FL_ALPHA_IS_UNCOMPRESSED); } diff --git a/drivers/media/platform/vicodec/codec-fwht.h b/drivers/media/platform/vicodec/codec-fwht.h index 90ff8962fca7..1da0a2384b48 100644 --- a/drivers/media/platform/vicodec/codec-fwht.h +++ b/drivers/media/platform/vicodec/codec-fwht.h @@ -81,6 +81,12 @@ #define FWHT_FL_COMPONENTS_NUM_MSK GENMASK(17, 16) #define FWHT_FL_COMPONENTS_NUM_OFFSET 16 +/* A macro to calculate the needed padding in order to make sure + * both luma and chroma components resolutions are rounded up to + * closest multiple of 8 + */ +#define vic_round_dim(dim, div) (round_up((dim) / (div), 8) * (div)) + struct fwht_cframe_hdr { u32 magic1; u32 magic2; @@ -112,6 +118,7 @@ struct fwht_raw_frame { unsigned int luma_alpha_step; unsigned int chroma_step; unsigned int components_num; + unsigned int stride; u8 *luma, *cb, *cr, *alpha; }; @@ -127,6 +134,6 @@ u32 fwht_encode_frame(struct fwht_raw_frame *frm, struct fwht_cframe *cf, bool is_intra, bool next_is_intra); void fwht_decode_frame(struct fwht_cframe *cf, struct fwht_raw_frame *ref, - u32 hdr_flags, unsigned int components_num); + u32 hdr_flags, unsigned int components_num, unsigned int stride); #endif diff --git a/drivers/media/platform/vicodec/codec-v4l2-fwht.c b/drivers/media/platform/vicodec/codec-v4l2-fwht.c index 8cb0212df67f..32a1216e66e6 100644 --- a/drivers/media/platform/vicodec/codec-v4l2-fwht.c +++ b/drivers/media/platform/vicodec/codec-v4l2-fwht.c @@ -56,7 +56,7 @@ const struct v4l2_fwht_pixfmt_info *v4l2_fwht_get_pixfmt(u32 idx) int v4l2_fwht_encode(struct v4l2_fwht_state *state, u8 *p_in, u8 *p_out) { - unsigned int size = state->width * state->height; + unsigned int size; const struct v4l2_fwht_pixfmt_info *info = state->info; struct fwht_cframe_hdr *p_hdr; struct fwht_cframe cf; @@ -66,8 +66,11 @@ int v4l2_fwht_encode(struct v4l2_fwht_state *state, u8 *p_in, u8 *p_out) if (!info) return -EINVAL; - rf.width = state->width; - rf.height = state->height; + + size = state->stride * state->padded_height; + rf.width = state->visible_width; + rf.height = state->visible_height; + rf.stride = state->stride; rf.luma = p_in; rf.width_div = info->width_div; rf.height_div = info->height_div; @@ -163,8 +166,8 @@ int v4l2_fwht_encode(struct v4l2_fwht_state *state, u8 *p_in, u8 *p_out) return -EINVAL; } - cf.width = state->width; - cf.height = state->height; + cf.width = state->visible_width; + cf.height = state->visible_height; cf.i_frame_qp = state->i_frame_qp; cf.p_frame_qp = state->p_frame_qp; cf.rlc_data = (__be16 *)(p_out + sizeof(*p_hdr)); @@ -209,8 +212,8 @@ int v4l2_fwht_encode(struct v4l2_fwht_state *state, u8 *p_in, u8 *p_out) int v4l2_fwht_decode(struct v4l2_fwht_state *state, u8 *p_in, u8 *p_out) { - unsigned int size = state->width * state->height; - unsigned int chroma_size = size; + unsigned int size; + unsigned int chroma_size; unsigned int i; u32 flags; struct fwht_cframe_hdr *p_hdr; @@ -218,10 +221,14 @@ int v4l2_fwht_decode(struct v4l2_fwht_state *state, u8 *p_in, u8 *p_out) u8 *p; unsigned int components_num = 3; unsigned int version; + const struct v4l2_fwht_pixfmt_info *info; if (!state->info) return -EINVAL; + info = state->info; + size = state->stride * state->padded_height; + chroma_size = size; p_hdr = (struct fwht_cframe_hdr *)p_in; cf.width = ntohl(p_hdr->width); cf.height = ntohl(p_hdr->height); @@ -234,12 +241,11 @@ int v4l2_fwht_decode(struct v4l2_fwht_state *state, u8 *p_in, u8 *p_out) } if (p_hdr->magic1 != FWHT_MAGIC1 || - p_hdr->magic2 != FWHT_MAGIC2 || - (cf.width & 7) || (cf.height & 7)) + p_hdr->magic2 != FWHT_MAGIC2) return -EINVAL; /* TODO: support resolution changes */ - if (cf.width != state->width || cf.height != state->height) + if (cf.width != state->visible_width || cf.height != state->visible_height) return -EINVAL; flags = ntohl(p_hdr->flags); @@ -260,7 +266,7 @@ int v4l2_fwht_decode(struct v4l2_fwht_state *state, u8 *p_in, u8 *p_out) if (!(flags & FWHT_FL_CHROMA_FULL_HEIGHT)) chroma_size /= 2; - fwht_decode_frame(&cf, &state->ref_frame, flags, components_num); + fwht_decode_frame(&cf, &state->ref_frame, flags, components_num, state->stride); /* * TODO - handle the case where the compressed stream encodes a diff --git a/drivers/media/platform/vicodec/codec-v4l2-fwht.h b/drivers/media/platform/vicodec/codec-v4l2-fwht.h index ed53e28d4f9c..d140ac770866 100644 --- a/drivers/media/platform/vicodec/codec-v4l2-fwht.h +++ b/drivers/media/platform/vicodec/codec-v4l2-fwht.h @@ -23,8 +23,10 @@ struct v4l2_fwht_pixfmt_info { struct v4l2_fwht_state { const struct v4l2_fwht_pixfmt_info *info; - unsigned int width; - unsigned int height; + unsigned int visible_width; + unsigned int visible_height; + unsigned int stride; + unsigned int padded_height; unsigned int gop_size; unsigned int gop_cnt; u16 i_frame_qp; diff --git a/drivers/media/platform/vicodec/vicodec-core.c b/drivers/media/platform/vicodec/vicodec-core.c index 0d7876f5acf0..e94f1a22f5b9 100644 --- a/drivers/media/platform/vicodec/vicodec-core.c +++ b/drivers/media/platform/vicodec/vicodec-core.c @@ -75,8 +75,10 @@ static struct platform_device vicodec_pdev = { /* Per-queue, driver-specific private data */ struct vicodec_q_data { - unsigned int width; - unsigned int height; + unsigned int coded_width; + unsigned int coded_height; + unsigned int visible_width; + unsigned int visible_height; unsigned int sizeimage; unsigned int sequence; const struct v4l2_fwht_pixfmt_info *info; @@ -464,11 +466,11 @@ static int vidioc_g_fmt(struct vicodec_ctx *ctx, struct v4l2_format *f) if (multiplanar) return -EINVAL; pix = &f->fmt.pix; - pix->width = q_data->width; - pix->height = q_data->height; + pix->width = vic_round_dim(q_data->coded_width, info->width_div); + pix->height = vic_round_dim(q_data->coded_height, info->height_div); pix->field = V4L2_FIELD_NONE; pix->pixelformat = info->id; - pix->bytesperline = q_data->width * info->bytesperline_mult; + pix->bytesperline = pix->width * info->bytesperline_mult; pix->sizeimage = q_data->sizeimage; pix->colorspace = ctx->state.colorspace; pix->xfer_func = ctx->state.xfer_func; @@ -481,13 +483,13 @@ static int vidioc_g_fmt(struct vicodec_ctx *ctx, struct v4l2_format *f) if (!multiplanar) return -EINVAL; pix_mp = &f->fmt.pix_mp; - pix_mp->width = q_data->width; - pix_mp->height = q_data->height; + pix_mp->width = vic_round_dim(q_data->coded_width, info->width_div); + pix_mp->height = vic_round_dim(q_data->coded_height, info->height_div); pix_mp->field = V4L2_FIELD_NONE; pix_mp->pixelformat = info->id; pix_mp->num_planes = 1; pix_mp->plane_fmt[0].bytesperline = - q_data->width * info->bytesperline_mult; + pix_mp->width * info->bytesperline_mult; pix_mp->plane_fmt[0].sizeimage = q_data->sizeimage; pix_mp->colorspace = ctx->state.colorspace; pix_mp->xfer_func = ctx->state.xfer_func; @@ -528,8 +530,8 @@ static int vidioc_try_fmt(struct vicodec_ctx *ctx, struct v4l2_format *f) pix = &f->fmt.pix; if (pix->pixelformat != V4L2_PIX_FMT_FWHT) info = find_fmt(pix->pixelformat); - pix->width = clamp(pix->width, MIN_WIDTH, MAX_WIDTH) & ~7; - pix->height = clamp(pix->height, MIN_HEIGHT, MAX_HEIGHT) & ~7; + pix->width = vic_round_dim(clamp(pix->width, MIN_WIDTH, MAX_WIDTH), info->width_div); + pix->height = vic_round_dim(clamp(pix->height, MIN_HEIGHT, MAX_HEIGHT), info->height_div); pix->field = V4L2_FIELD_NONE; pix->bytesperline = pix->width * info->bytesperline_mult; @@ -545,9 +547,8 @@ static int vidioc_try_fmt(struct vicodec_ctx *ctx, struct v4l2_format *f) if (pix_mp->pixelformat != V4L2_PIX_FMT_FWHT) info = find_fmt(pix_mp->pixelformat); pix_mp->num_planes = 1; - pix_mp->width = clamp(pix_mp->width, MIN_WIDTH, MAX_WIDTH) & ~7; - pix_mp->height = - clamp(pix_mp->height, MIN_HEIGHT, MAX_HEIGHT) & ~7; + pix_mp->width = vic_round_dim(clamp(pix_mp->width, MIN_WIDTH, MAX_WIDTH), info->width_div); + pix_mp->height = vic_round_dim(clamp(pix->height, MIN_HEIGHT, MAX_HEIGHT), info->height_div); pix_mp->field = V4L2_FIELD_NONE; plane->bytesperline = pix_mp->width * info->bytesperline_mult; @@ -635,13 +636,15 @@ static int vidioc_try_fmt_vid_out(struct file *file, void *priv, return vidioc_try_fmt(ctx, f); } -static int vidioc_s_fmt(struct vicodec_ctx *ctx, struct v4l2_format *f) +static int vidioc_s_fmt(struct vicodec_ctx *ctx, struct v4l2_format *f, + unsigned int orig_width, unsigned int orig_height) { struct vicodec_q_data *q_data; struct vb2_queue *vq; bool fmt_changed = true; struct v4l2_pix_format_mplane *pix_mp; struct v4l2_pix_format *pix; + const struct v4l2_fwht_pixfmt_info *info; vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); if (!vq) @@ -650,6 +653,7 @@ static int vidioc_s_fmt(struct vicodec_ctx *ctx, struct v4l2_format *f) q_data = get_q_data(ctx, f->type); if (!q_data) return -EINVAL; + info = q_data->info; switch (f->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: @@ -658,8 +662,8 @@ static int vidioc_s_fmt(struct vicodec_ctx *ctx, struct v4l2_format *f) if (ctx->is_enc && V4L2_TYPE_IS_OUTPUT(f->type)) fmt_changed = q_data->info->id != pix->pixelformat || - q_data->width != pix->width || - q_data->height != pix->height; + vic_round_dim(q_data->coded_width, info->width_div) != pix->width || + vic_round_dim(q_data->coded_height, info->height_div) != pix->height; if (vb2_is_busy(vq) && fmt_changed) return -EBUSY; @@ -668,8 +672,13 @@ static int vidioc_s_fmt(struct vicodec_ctx *ctx, struct v4l2_format *f) q_data->info = &pixfmt_fwht; else q_data->info = find_fmt(pix->pixelformat); - q_data->width = pix->width; - q_data->height = pix->height; + + q_data->coded_width = orig_width; + if (q_data->visible_width > orig_width) + q_data->visible_width = orig_width; + q_data->coded_height = orig_height; + if (q_data->visible_height > orig_height) + q_data->visible_height = orig_height; q_data->sizeimage = pix->sizeimage; break; case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: @@ -678,8 +687,8 @@ static int vidioc_s_fmt(struct vicodec_ctx *ctx, struct v4l2_format *f) if (ctx->is_enc && V4L2_TYPE_IS_OUTPUT(f->type)) fmt_changed = q_data->info->id != pix_mp->pixelformat || - q_data->width != pix_mp->width || - q_data->height != pix_mp->height; + vic_round_dim(q_data->coded_width, info->width_div) != pix_mp->width || + vic_round_dim(q_data->coded_height, info->height_div) != pix_mp->height; if (vb2_is_busy(vq) && fmt_changed) return -EBUSY; @@ -688,8 +697,8 @@ static int vidioc_s_fmt(struct vicodec_ctx *ctx, struct v4l2_format *f) q_data->info = &pixfmt_fwht; else q_data->info = find_fmt(pix_mp->pixelformat); - q_data->width = pix_mp->width; - q_data->height = pix_mp->height; + q_data->coded_width = orig_width; + q_data->coded_height = orig_height; q_data->sizeimage = pix_mp->plane_fmt[0].sizeimage; break; default: @@ -698,7 +707,7 @@ static int vidioc_s_fmt(struct vicodec_ctx *ctx, struct v4l2_format *f) dprintk(ctx->dev, "Setting format for type %d, wxh: %dx%d, fourcc: %08x\n", - f->type, q_data->width, q_data->height, q_data->info->id); + f->type, q_data->coded_width, q_data->coded_height, q_data->info->id); return 0; } @@ -707,12 +716,27 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { int ret; + unsigned int orig_width, orig_height; + switch (f->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + orig_width = f->fmt.pix.width; + orig_height = f->fmt.pix.height; + break; + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + orig_width = f->fmt.pix_mp.width; + orig_height = f->fmt.pix_mp.height; + break; + default: + break; + } ret = vidioc_try_fmt_vid_cap(file, priv, f); if (ret) return ret; - return vidioc_s_fmt(file2ctx(file), f); + return vidioc_s_fmt(file2ctx(file), f, orig_width, orig_height); } static int vidioc_s_fmt_vid_out(struct file *file, void *priv, @@ -721,36 +745,128 @@ static int vidioc_s_fmt_vid_out(struct file *file, void *priv, struct vicodec_ctx *ctx = file2ctx(file); struct v4l2_pix_format_mplane *pix_mp; struct v4l2_pix_format *pix; + unsigned int orig_width, orig_height; int ret; - ret = vidioc_try_fmt_vid_out(file, priv, f); - if (ret) - return ret; + switch (f->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + pix = &f->fmt.pix; + orig_width = pix->width; + orig_height = pix->height; + ret = vidioc_try_fmt_vid_out(file, priv, f); + if (ret) + return ret; + ret = vidioc_s_fmt(file2ctx(file), f, orig_width, orig_height); + if (ret) + return ret; + ctx->state.colorspace = pix->colorspace; + ctx->state.xfer_func = pix->xfer_func; + ctx->state.ycbcr_enc = pix->ycbcr_enc; + ctx->state.quantization = pix->quantization; + break; + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + pix_mp = &f->fmt.pix_mp; + orig_width = pix_mp->width; + orig_height = pix_mp->height; + ret = vidioc_try_fmt_vid_out(file, priv, f); + if (ret) + return ret; + ret = vidioc_s_fmt(file2ctx(file), f, orig_width, orig_height); + if (ret) + return ret; + ctx->state.colorspace = pix_mp->colorspace; + ctx->state.xfer_func = pix_mp->xfer_func; + ctx->state.ycbcr_enc = pix_mp->ycbcr_enc; + ctx->state.quantization = pix_mp->quantization; + break; + default: + break; + } + return ret; +} - ret = vidioc_s_fmt(file2ctx(file), f); - if (!ret) { - switch (f->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - case V4L2_BUF_TYPE_VIDEO_OUTPUT: - pix = &f->fmt.pix; - ctx->state.colorspace = pix->colorspace; - ctx->state.xfer_func = pix->xfer_func; - ctx->state.ycbcr_enc = pix->ycbcr_enc; - ctx->state.quantization = pix->quantization; - break; - case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: - case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - pix_mp = &f->fmt.pix_mp; - ctx->state.colorspace = pix_mp->colorspace; - ctx->state.xfer_func = pix_mp->xfer_func; - ctx->state.ycbcr_enc = pix_mp->ycbcr_enc; - ctx->state.quantization = pix_mp->quantization; - break; +static int vidioc_g_selection(struct file *file, void *priv, + struct v4l2_selection *s) +{ + struct vicodec_ctx *ctx = file2ctx(file); + struct vicodec_q_data *q_data; + + q_data = get_q_data(ctx, s->type); + if (!q_data) + return -EINVAL; + + /* encoder supports only cropping on the OUTPUT buffer */ + if (ctx->is_enc && s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { + switch (s->target) { + case V4L2_SEL_TGT_CROP_DEFAULT: + case V4L2_SEL_TGT_CROP_BOUNDS: + s->r.left = 0; + s->r.top = 0; + s->r.width = q_data->coded_width; + s->r.height = q_data->coded_height; + return 0; + case V4L2_SEL_TGT_CROP: + s->r.left = 0; + s->r.top = 0; + s->r.width = q_data->visible_width; + s->r.height = q_data->visible_height; + return 0; default: - break; + return -EINVAL; + } + /* decoder supports only composing on the CAPTURE buffer */ + } else if (!ctx->is_enc && s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { + switch (s->target) { + case V4L2_SEL_TGT_COMPOSE: + case V4L2_SEL_TGT_COMPOSE_DEFAULT: + case V4L2_SEL_TGT_COMPOSE_BOUNDS: + s->r.left = 0; + s->r.top = 0; + s->r.width = q_data->coded_width; + s->r.height = q_data->coded_height; + return 0; + default: + return -EINVAL; } } - return ret; + return -EINVAL; +} + +static int vidioc_s_selection(struct file *file, void *priv, + struct v4l2_selection *s) +{ + struct vicodec_ctx *ctx = file2ctx(file); + struct vicodec_q_data *q_data; + + q_data = get_q_data(ctx, s->type); + if (!q_data) + return -EINVAL; + + /* encoder supports only cropping on the OUTPUT buffer */ + if (ctx->is_enc && s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { + switch (s->target) { + case V4L2_SEL_TGT_CROP: + s->r.left = 0; + s->r.top = 0; + q_data->visible_width = clamp(s->r.width, MIN_WIDTH, q_data->coded_width); + s->r.width = q_data->visible_width; + q_data->visible_height = clamp(s->r.height, MIN_HEIGHT, q_data->coded_height); + s->r.height = q_data->visible_height; + return 0; + default: + return -EINVAL; + } + /* decoder supports only composing on the CAPTURE buffer */ + } else if (!ctx->is_enc && s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { + /* TODO - enable COMOPOSE setting on the capture buffer */ + s->r.left = 0; + s->r.top = 0; + s->r.width = q_data->coded_width; + s->r.height = q_data->coded_height; + } + return -EINVAL; } static void vicodec_mark_last_buf(struct vicodec_ctx *ctx) @@ -895,6 +1011,9 @@ static const struct v4l2_ioctl_ops vicodec_ioctl_ops = { .vidioc_streamon = v4l2_m2m_ioctl_streamon, .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, + .vidioc_g_selection = vidioc_g_selection, + .vidioc_s_selection = vidioc_s_selection, + .vidioc_try_encoder_cmd = vicodec_try_encoder_cmd, .vidioc_encoder_cmd = vicodec_encoder_cmd, .vidioc_try_decoder_cmd = vicodec_try_decoder_cmd, @@ -988,8 +1107,9 @@ static int vicodec_start_streaming(struct vb2_queue *q, struct vicodec_ctx *ctx = vb2_get_drv_priv(q); struct vicodec_q_data *q_data = get_q_data(ctx, q->type); struct v4l2_fwht_state *state = &ctx->state; - unsigned int size = q_data->width * q_data->height; const struct v4l2_fwht_pixfmt_info *info = q_data->info; + unsigned int size = vic_round_dim(q_data->coded_width, info->width_div) * + vic_round_dim(q_data->coded_height, info->height_div); unsigned int chroma_div = info->width_div * info->height_div; unsigned int total_planes_size; @@ -1008,15 +1128,20 @@ static int vicodec_start_streaming(struct vb2_queue *q, if (!V4L2_TYPE_IS_OUTPUT(q->type)) { if (!ctx->is_enc) { - state->width = q_data->width; - state->height = q_data->height; + state->visible_width = q_data->coded_width; + state->visible_height = q_data->coded_height; + state->stride = vic_round_dim(q_data->coded_width, info->width_div); + state->padded_height = vic_round_dim(q_data->coded_height, info->height_div); + } return 0; } if (ctx->is_enc) { - state->width = q_data->width; - state->height = q_data->height; + state->visible_width = q_data->visible_width; + state->visible_height = q_data->visible_height; + state->stride = vic_round_dim(q_data->coded_width, info->width_div); + state->padded_height = vic_round_dim(q_data->coded_height, info->height_div); } state->ref_frame.width = state->ref_frame.height = 0; state->ref_frame.luma = kvmalloc(total_planes_size, GFP_KERNEL); @@ -1204,8 +1329,10 @@ static int vicodec_open(struct file *file) ctx->q_data[V4L2_M2M_SRC].info = ctx->is_enc ? v4l2_fwht_get_pixfmt(0) : &pixfmt_fwht; - ctx->q_data[V4L2_M2M_SRC].width = 1280; - ctx->q_data[V4L2_M2M_SRC].height = 720; + ctx->q_data[V4L2_M2M_SRC].coded_width = 1280; + ctx->q_data[V4L2_M2M_SRC].coded_height = 720; + ctx->q_data[V4L2_M2M_SRC].visible_width = 1280; + ctx->q_data[V4L2_M2M_SRC].visible_height = 720; size = 1280 * 720 * ctx->q_data[V4L2_M2M_SRC].info->sizeimage_mult / ctx->q_data[V4L2_M2M_SRC].info->sizeimage_div; if (ctx->is_enc)