162306a36Sopenharmony_ci// SPDX-License-Identifier: LGPL-2.1 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * A V4L2 frontend for the FWHT codec 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright 2018 Cisco Systems, Inc. and/or its affiliates. All rights reserved. 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/errno.h> 962306a36Sopenharmony_ci#include <linux/string.h> 1062306a36Sopenharmony_ci#include <linux/videodev2.h> 1162306a36Sopenharmony_ci#include "codec-v4l2-fwht.h" 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_cistatic const struct v4l2_fwht_pixfmt_info v4l2_fwht_pixfmts[] = { 1462306a36Sopenharmony_ci { V4L2_PIX_FMT_YUV420, 1, 3, 2, 1, 1, 2, 2, 3, 3, V4L2_FWHT_FL_PIXENC_YUV}, 1562306a36Sopenharmony_ci { V4L2_PIX_FMT_YVU420, 1, 3, 2, 1, 1, 2, 2, 3, 3, V4L2_FWHT_FL_PIXENC_YUV}, 1662306a36Sopenharmony_ci { V4L2_PIX_FMT_YUV422P, 1, 2, 1, 1, 1, 2, 1, 3, 3, V4L2_FWHT_FL_PIXENC_YUV}, 1762306a36Sopenharmony_ci { V4L2_PIX_FMT_NV12, 1, 3, 2, 1, 2, 2, 2, 3, 2, V4L2_FWHT_FL_PIXENC_YUV}, 1862306a36Sopenharmony_ci { V4L2_PIX_FMT_NV21, 1, 3, 2, 1, 2, 2, 2, 3, 2, V4L2_FWHT_FL_PIXENC_YUV}, 1962306a36Sopenharmony_ci { V4L2_PIX_FMT_NV16, 1, 2, 1, 1, 2, 2, 1, 3, 2, V4L2_FWHT_FL_PIXENC_YUV}, 2062306a36Sopenharmony_ci { V4L2_PIX_FMT_NV61, 1, 2, 1, 1, 2, 2, 1, 3, 2, V4L2_FWHT_FL_PIXENC_YUV}, 2162306a36Sopenharmony_ci { V4L2_PIX_FMT_NV24, 1, 3, 1, 1, 2, 1, 1, 3, 2, V4L2_FWHT_FL_PIXENC_YUV}, 2262306a36Sopenharmony_ci { V4L2_PIX_FMT_NV42, 1, 3, 1, 1, 2, 1, 1, 3, 2, V4L2_FWHT_FL_PIXENC_YUV}, 2362306a36Sopenharmony_ci { V4L2_PIX_FMT_YUYV, 2, 2, 1, 2, 4, 2, 1, 3, 1, V4L2_FWHT_FL_PIXENC_YUV}, 2462306a36Sopenharmony_ci { V4L2_PIX_FMT_YVYU, 2, 2, 1, 2, 4, 2, 1, 3, 1, V4L2_FWHT_FL_PIXENC_YUV}, 2562306a36Sopenharmony_ci { V4L2_PIX_FMT_UYVY, 2, 2, 1, 2, 4, 2, 1, 3, 1, V4L2_FWHT_FL_PIXENC_YUV}, 2662306a36Sopenharmony_ci { V4L2_PIX_FMT_VYUY, 2, 2, 1, 2, 4, 2, 1, 3, 1, V4L2_FWHT_FL_PIXENC_YUV}, 2762306a36Sopenharmony_ci { V4L2_PIX_FMT_BGR24, 3, 3, 1, 3, 3, 1, 1, 3, 1, V4L2_FWHT_FL_PIXENC_RGB}, 2862306a36Sopenharmony_ci { V4L2_PIX_FMT_RGB24, 3, 3, 1, 3, 3, 1, 1, 3, 1, V4L2_FWHT_FL_PIXENC_RGB}, 2962306a36Sopenharmony_ci { V4L2_PIX_FMT_HSV24, 3, 3, 1, 3, 3, 1, 1, 3, 1, V4L2_FWHT_FL_PIXENC_HSV}, 3062306a36Sopenharmony_ci { V4L2_PIX_FMT_BGR32, 4, 4, 1, 4, 4, 1, 1, 4, 1, V4L2_FWHT_FL_PIXENC_RGB}, 3162306a36Sopenharmony_ci { V4L2_PIX_FMT_XBGR32, 4, 4, 1, 4, 4, 1, 1, 4, 1, V4L2_FWHT_FL_PIXENC_RGB}, 3262306a36Sopenharmony_ci { V4L2_PIX_FMT_ABGR32, 4, 4, 1, 4, 4, 1, 1, 4, 1, V4L2_FWHT_FL_PIXENC_RGB}, 3362306a36Sopenharmony_ci { V4L2_PIX_FMT_RGB32, 4, 4, 1, 4, 4, 1, 1, 4, 1, V4L2_FWHT_FL_PIXENC_RGB}, 3462306a36Sopenharmony_ci { V4L2_PIX_FMT_XRGB32, 4, 4, 1, 4, 4, 1, 1, 4, 1, V4L2_FWHT_FL_PIXENC_RGB}, 3562306a36Sopenharmony_ci { V4L2_PIX_FMT_ARGB32, 4, 4, 1, 4, 4, 1, 1, 4, 1, V4L2_FWHT_FL_PIXENC_RGB}, 3662306a36Sopenharmony_ci { V4L2_PIX_FMT_BGRX32, 4, 4, 1, 4, 4, 1, 1, 4, 1, V4L2_FWHT_FL_PIXENC_RGB}, 3762306a36Sopenharmony_ci { V4L2_PIX_FMT_BGRA32, 4, 4, 1, 4, 4, 1, 1, 4, 1, V4L2_FWHT_FL_PIXENC_RGB}, 3862306a36Sopenharmony_ci { V4L2_PIX_FMT_RGBX32, 4, 4, 1, 4, 4, 1, 1, 4, 1, V4L2_FWHT_FL_PIXENC_RGB}, 3962306a36Sopenharmony_ci { V4L2_PIX_FMT_RGBA32, 4, 4, 1, 4, 4, 1, 1, 4, 1, V4L2_FWHT_FL_PIXENC_RGB}, 4062306a36Sopenharmony_ci { V4L2_PIX_FMT_HSV32, 4, 4, 1, 4, 4, 1, 1, 4, 1, V4L2_FWHT_FL_PIXENC_HSV}, 4162306a36Sopenharmony_ci { V4L2_PIX_FMT_GREY, 1, 1, 1, 1, 0, 1, 1, 1, 1, V4L2_FWHT_FL_PIXENC_RGB}, 4262306a36Sopenharmony_ci}; 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_cibool v4l2_fwht_validate_fmt(const struct v4l2_fwht_pixfmt_info *info, 4562306a36Sopenharmony_ci u32 width_div, u32 height_div, u32 components_num, 4662306a36Sopenharmony_ci u32 pixenc) 4762306a36Sopenharmony_ci{ 4862306a36Sopenharmony_ci if (info->width_div == width_div && 4962306a36Sopenharmony_ci info->height_div == height_div && 5062306a36Sopenharmony_ci (!pixenc || info->pixenc == pixenc) && 5162306a36Sopenharmony_ci info->components_num == components_num) 5262306a36Sopenharmony_ci return true; 5362306a36Sopenharmony_ci return false; 5462306a36Sopenharmony_ci} 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ciconst struct v4l2_fwht_pixfmt_info *v4l2_fwht_find_nth_fmt(u32 width_div, 5762306a36Sopenharmony_ci u32 height_div, 5862306a36Sopenharmony_ci u32 components_num, 5962306a36Sopenharmony_ci u32 pixenc, 6062306a36Sopenharmony_ci unsigned int start_idx) 6162306a36Sopenharmony_ci{ 6262306a36Sopenharmony_ci unsigned int i; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(v4l2_fwht_pixfmts); i++) { 6562306a36Sopenharmony_ci bool is_valid = v4l2_fwht_validate_fmt(&v4l2_fwht_pixfmts[i], 6662306a36Sopenharmony_ci width_div, height_div, 6762306a36Sopenharmony_ci components_num, pixenc); 6862306a36Sopenharmony_ci if (is_valid) { 6962306a36Sopenharmony_ci if (start_idx == 0) 7062306a36Sopenharmony_ci return v4l2_fwht_pixfmts + i; 7162306a36Sopenharmony_ci start_idx--; 7262306a36Sopenharmony_ci } 7362306a36Sopenharmony_ci } 7462306a36Sopenharmony_ci return NULL; 7562306a36Sopenharmony_ci} 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ciconst struct v4l2_fwht_pixfmt_info *v4l2_fwht_find_pixfmt(u32 pixelformat) 7862306a36Sopenharmony_ci{ 7962306a36Sopenharmony_ci unsigned int i; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(v4l2_fwht_pixfmts); i++) 8262306a36Sopenharmony_ci if (v4l2_fwht_pixfmts[i].id == pixelformat) 8362306a36Sopenharmony_ci return v4l2_fwht_pixfmts + i; 8462306a36Sopenharmony_ci return NULL; 8562306a36Sopenharmony_ci} 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ciconst struct v4l2_fwht_pixfmt_info *v4l2_fwht_get_pixfmt(u32 idx) 8862306a36Sopenharmony_ci{ 8962306a36Sopenharmony_ci if (idx >= ARRAY_SIZE(v4l2_fwht_pixfmts)) 9062306a36Sopenharmony_ci return NULL; 9162306a36Sopenharmony_ci return v4l2_fwht_pixfmts + idx; 9262306a36Sopenharmony_ci} 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_cistatic int prepare_raw_frame(struct fwht_raw_frame *rf, 9562306a36Sopenharmony_ci const struct v4l2_fwht_pixfmt_info *info, u8 *buf, 9662306a36Sopenharmony_ci unsigned int size) 9762306a36Sopenharmony_ci{ 9862306a36Sopenharmony_ci rf->luma = buf; 9962306a36Sopenharmony_ci rf->width_div = info->width_div; 10062306a36Sopenharmony_ci rf->height_div = info->height_div; 10162306a36Sopenharmony_ci rf->luma_alpha_step = info->luma_alpha_step; 10262306a36Sopenharmony_ci rf->chroma_step = info->chroma_step; 10362306a36Sopenharmony_ci rf->alpha = NULL; 10462306a36Sopenharmony_ci rf->components_num = info->components_num; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci /* 10762306a36Sopenharmony_ci * The buffer is NULL if it is the reference 10862306a36Sopenharmony_ci * frame of an I-frame in the stateless decoder 10962306a36Sopenharmony_ci */ 11062306a36Sopenharmony_ci if (!buf) { 11162306a36Sopenharmony_ci rf->luma = NULL; 11262306a36Sopenharmony_ci rf->cb = NULL; 11362306a36Sopenharmony_ci rf->cr = NULL; 11462306a36Sopenharmony_ci rf->alpha = NULL; 11562306a36Sopenharmony_ci return 0; 11662306a36Sopenharmony_ci } 11762306a36Sopenharmony_ci switch (info->id) { 11862306a36Sopenharmony_ci case V4L2_PIX_FMT_GREY: 11962306a36Sopenharmony_ci rf->cb = NULL; 12062306a36Sopenharmony_ci rf->cr = NULL; 12162306a36Sopenharmony_ci break; 12262306a36Sopenharmony_ci case V4L2_PIX_FMT_YUV420: 12362306a36Sopenharmony_ci rf->cb = rf->luma + size; 12462306a36Sopenharmony_ci rf->cr = rf->cb + size / 4; 12562306a36Sopenharmony_ci break; 12662306a36Sopenharmony_ci case V4L2_PIX_FMT_YVU420: 12762306a36Sopenharmony_ci rf->cr = rf->luma + size; 12862306a36Sopenharmony_ci rf->cb = rf->cr + size / 4; 12962306a36Sopenharmony_ci break; 13062306a36Sopenharmony_ci case V4L2_PIX_FMT_YUV422P: 13162306a36Sopenharmony_ci rf->cb = rf->luma + size; 13262306a36Sopenharmony_ci rf->cr = rf->cb + size / 2; 13362306a36Sopenharmony_ci break; 13462306a36Sopenharmony_ci case V4L2_PIX_FMT_NV12: 13562306a36Sopenharmony_ci case V4L2_PIX_FMT_NV16: 13662306a36Sopenharmony_ci case V4L2_PIX_FMT_NV24: 13762306a36Sopenharmony_ci rf->cb = rf->luma + size; 13862306a36Sopenharmony_ci rf->cr = rf->cb + 1; 13962306a36Sopenharmony_ci break; 14062306a36Sopenharmony_ci case V4L2_PIX_FMT_NV21: 14162306a36Sopenharmony_ci case V4L2_PIX_FMT_NV61: 14262306a36Sopenharmony_ci case V4L2_PIX_FMT_NV42: 14362306a36Sopenharmony_ci rf->cr = rf->luma + size; 14462306a36Sopenharmony_ci rf->cb = rf->cr + 1; 14562306a36Sopenharmony_ci break; 14662306a36Sopenharmony_ci case V4L2_PIX_FMT_YUYV: 14762306a36Sopenharmony_ci rf->cb = rf->luma + 1; 14862306a36Sopenharmony_ci rf->cr = rf->cb + 2; 14962306a36Sopenharmony_ci break; 15062306a36Sopenharmony_ci case V4L2_PIX_FMT_YVYU: 15162306a36Sopenharmony_ci rf->cr = rf->luma + 1; 15262306a36Sopenharmony_ci rf->cb = rf->cr + 2; 15362306a36Sopenharmony_ci break; 15462306a36Sopenharmony_ci case V4L2_PIX_FMT_UYVY: 15562306a36Sopenharmony_ci rf->cb = rf->luma; 15662306a36Sopenharmony_ci rf->cr = rf->cb + 2; 15762306a36Sopenharmony_ci rf->luma++; 15862306a36Sopenharmony_ci break; 15962306a36Sopenharmony_ci case V4L2_PIX_FMT_VYUY: 16062306a36Sopenharmony_ci rf->cr = rf->luma; 16162306a36Sopenharmony_ci rf->cb = rf->cr + 2; 16262306a36Sopenharmony_ci rf->luma++; 16362306a36Sopenharmony_ci break; 16462306a36Sopenharmony_ci case V4L2_PIX_FMT_RGB24: 16562306a36Sopenharmony_ci case V4L2_PIX_FMT_HSV24: 16662306a36Sopenharmony_ci rf->cr = rf->luma; 16762306a36Sopenharmony_ci rf->cb = rf->cr + 2; 16862306a36Sopenharmony_ci rf->luma++; 16962306a36Sopenharmony_ci break; 17062306a36Sopenharmony_ci case V4L2_PIX_FMT_BGR24: 17162306a36Sopenharmony_ci rf->cb = rf->luma; 17262306a36Sopenharmony_ci rf->cr = rf->cb + 2; 17362306a36Sopenharmony_ci rf->luma++; 17462306a36Sopenharmony_ci break; 17562306a36Sopenharmony_ci case V4L2_PIX_FMT_RGB32: 17662306a36Sopenharmony_ci case V4L2_PIX_FMT_XRGB32: 17762306a36Sopenharmony_ci case V4L2_PIX_FMT_HSV32: 17862306a36Sopenharmony_ci case V4L2_PIX_FMT_ARGB32: 17962306a36Sopenharmony_ci rf->alpha = rf->luma; 18062306a36Sopenharmony_ci rf->cr = rf->luma + 1; 18162306a36Sopenharmony_ci rf->cb = rf->cr + 2; 18262306a36Sopenharmony_ci rf->luma += 2; 18362306a36Sopenharmony_ci break; 18462306a36Sopenharmony_ci case V4L2_PIX_FMT_BGR32: 18562306a36Sopenharmony_ci case V4L2_PIX_FMT_XBGR32: 18662306a36Sopenharmony_ci case V4L2_PIX_FMT_ABGR32: 18762306a36Sopenharmony_ci rf->cb = rf->luma; 18862306a36Sopenharmony_ci rf->cr = rf->cb + 2; 18962306a36Sopenharmony_ci rf->luma++; 19062306a36Sopenharmony_ci rf->alpha = rf->cr + 1; 19162306a36Sopenharmony_ci break; 19262306a36Sopenharmony_ci case V4L2_PIX_FMT_BGRX32: 19362306a36Sopenharmony_ci case V4L2_PIX_FMT_BGRA32: 19462306a36Sopenharmony_ci rf->alpha = rf->luma; 19562306a36Sopenharmony_ci rf->cb = rf->luma + 1; 19662306a36Sopenharmony_ci rf->cr = rf->cb + 2; 19762306a36Sopenharmony_ci rf->luma += 2; 19862306a36Sopenharmony_ci break; 19962306a36Sopenharmony_ci case V4L2_PIX_FMT_RGBX32: 20062306a36Sopenharmony_ci case V4L2_PIX_FMT_RGBA32: 20162306a36Sopenharmony_ci rf->alpha = rf->luma + 3; 20262306a36Sopenharmony_ci rf->cr = rf->luma; 20362306a36Sopenharmony_ci rf->cb = rf->cr + 2; 20462306a36Sopenharmony_ci rf->luma++; 20562306a36Sopenharmony_ci break; 20662306a36Sopenharmony_ci default: 20762306a36Sopenharmony_ci return -EINVAL; 20862306a36Sopenharmony_ci } 20962306a36Sopenharmony_ci return 0; 21062306a36Sopenharmony_ci} 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ciint v4l2_fwht_encode(struct v4l2_fwht_state *state, u8 *p_in, u8 *p_out) 21362306a36Sopenharmony_ci{ 21462306a36Sopenharmony_ci unsigned int size = state->stride * state->coded_height; 21562306a36Sopenharmony_ci unsigned int chroma_stride = state->stride; 21662306a36Sopenharmony_ci const struct v4l2_fwht_pixfmt_info *info = state->info; 21762306a36Sopenharmony_ci struct fwht_cframe_hdr *p_hdr; 21862306a36Sopenharmony_ci struct fwht_cframe cf; 21962306a36Sopenharmony_ci struct fwht_raw_frame rf; 22062306a36Sopenharmony_ci u32 encoding; 22162306a36Sopenharmony_ci u32 flags = 0; 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci if (!info) 22462306a36Sopenharmony_ci return -EINVAL; 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci if (prepare_raw_frame(&rf, info, p_in, size)) 22762306a36Sopenharmony_ci return -EINVAL; 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci if (info->planes_num == 3) 23062306a36Sopenharmony_ci chroma_stride /= 2; 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci if (info->id == V4L2_PIX_FMT_NV24 || 23362306a36Sopenharmony_ci info->id == V4L2_PIX_FMT_NV42) 23462306a36Sopenharmony_ci chroma_stride *= 2; 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci cf.i_frame_qp = state->i_frame_qp; 23762306a36Sopenharmony_ci cf.p_frame_qp = state->p_frame_qp; 23862306a36Sopenharmony_ci cf.rlc_data = (__be16 *)(p_out + sizeof(*p_hdr)); 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci encoding = fwht_encode_frame(&rf, &state->ref_frame, &cf, 24162306a36Sopenharmony_ci !state->gop_cnt, 24262306a36Sopenharmony_ci state->gop_cnt == state->gop_size - 1, 24362306a36Sopenharmony_ci state->visible_width, 24462306a36Sopenharmony_ci state->visible_height, 24562306a36Sopenharmony_ci state->stride, chroma_stride); 24662306a36Sopenharmony_ci if (!(encoding & FWHT_FRAME_PCODED)) 24762306a36Sopenharmony_ci state->gop_cnt = 0; 24862306a36Sopenharmony_ci if (++state->gop_cnt >= state->gop_size) 24962306a36Sopenharmony_ci state->gop_cnt = 0; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci p_hdr = (struct fwht_cframe_hdr *)p_out; 25262306a36Sopenharmony_ci p_hdr->magic1 = FWHT_MAGIC1; 25362306a36Sopenharmony_ci p_hdr->magic2 = FWHT_MAGIC2; 25462306a36Sopenharmony_ci p_hdr->version = htonl(V4L2_FWHT_VERSION); 25562306a36Sopenharmony_ci p_hdr->width = htonl(state->visible_width); 25662306a36Sopenharmony_ci p_hdr->height = htonl(state->visible_height); 25762306a36Sopenharmony_ci flags |= (info->components_num - 1) << V4L2_FWHT_FL_COMPONENTS_NUM_OFFSET; 25862306a36Sopenharmony_ci flags |= info->pixenc; 25962306a36Sopenharmony_ci if (encoding & FWHT_LUMA_UNENCODED) 26062306a36Sopenharmony_ci flags |= V4L2_FWHT_FL_LUMA_IS_UNCOMPRESSED; 26162306a36Sopenharmony_ci if (encoding & FWHT_CB_UNENCODED) 26262306a36Sopenharmony_ci flags |= V4L2_FWHT_FL_CB_IS_UNCOMPRESSED; 26362306a36Sopenharmony_ci if (encoding & FWHT_CR_UNENCODED) 26462306a36Sopenharmony_ci flags |= V4L2_FWHT_FL_CR_IS_UNCOMPRESSED; 26562306a36Sopenharmony_ci if (encoding & FWHT_ALPHA_UNENCODED) 26662306a36Sopenharmony_ci flags |= V4L2_FWHT_FL_ALPHA_IS_UNCOMPRESSED; 26762306a36Sopenharmony_ci if (!(encoding & FWHT_FRAME_PCODED)) 26862306a36Sopenharmony_ci flags |= V4L2_FWHT_FL_I_FRAME; 26962306a36Sopenharmony_ci if (rf.height_div == 1) 27062306a36Sopenharmony_ci flags |= V4L2_FWHT_FL_CHROMA_FULL_HEIGHT; 27162306a36Sopenharmony_ci if (rf.width_div == 1) 27262306a36Sopenharmony_ci flags |= V4L2_FWHT_FL_CHROMA_FULL_WIDTH; 27362306a36Sopenharmony_ci p_hdr->flags = htonl(flags); 27462306a36Sopenharmony_ci p_hdr->colorspace = htonl(state->colorspace); 27562306a36Sopenharmony_ci p_hdr->xfer_func = htonl(state->xfer_func); 27662306a36Sopenharmony_ci p_hdr->ycbcr_enc = htonl(state->ycbcr_enc); 27762306a36Sopenharmony_ci p_hdr->quantization = htonl(state->quantization); 27862306a36Sopenharmony_ci p_hdr->size = htonl(cf.size); 27962306a36Sopenharmony_ci return cf.size + sizeof(*p_hdr); 28062306a36Sopenharmony_ci} 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ciint v4l2_fwht_decode(struct v4l2_fwht_state *state, u8 *p_in, u8 *p_out) 28362306a36Sopenharmony_ci{ 28462306a36Sopenharmony_ci u32 flags; 28562306a36Sopenharmony_ci struct fwht_cframe cf; 28662306a36Sopenharmony_ci unsigned int components_num = 3; 28762306a36Sopenharmony_ci unsigned int version; 28862306a36Sopenharmony_ci const struct v4l2_fwht_pixfmt_info *info; 28962306a36Sopenharmony_ci unsigned int hdr_width_div, hdr_height_div; 29062306a36Sopenharmony_ci struct fwht_raw_frame dst_rf; 29162306a36Sopenharmony_ci unsigned int dst_chroma_stride = state->stride; 29262306a36Sopenharmony_ci unsigned int ref_chroma_stride = state->ref_stride; 29362306a36Sopenharmony_ci unsigned int dst_size = state->stride * state->coded_height; 29462306a36Sopenharmony_ci unsigned int ref_size; 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci if (!state->info) 29762306a36Sopenharmony_ci return -EINVAL; 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci info = state->info; 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci version = ntohl(state->header.version); 30262306a36Sopenharmony_ci if (!version || version > V4L2_FWHT_VERSION) { 30362306a36Sopenharmony_ci pr_err("version %d is not supported, current version is %d\n", 30462306a36Sopenharmony_ci version, V4L2_FWHT_VERSION); 30562306a36Sopenharmony_ci return -EINVAL; 30662306a36Sopenharmony_ci } 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci if (state->header.magic1 != FWHT_MAGIC1 || 30962306a36Sopenharmony_ci state->header.magic2 != FWHT_MAGIC2) 31062306a36Sopenharmony_ci return -EINVAL; 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci /* TODO: support resolution changes */ 31362306a36Sopenharmony_ci if (ntohl(state->header.width) != state->visible_width || 31462306a36Sopenharmony_ci ntohl(state->header.height) != state->visible_height) 31562306a36Sopenharmony_ci return -EINVAL; 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci flags = ntohl(state->header.flags); 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci if (version >= 2) { 32062306a36Sopenharmony_ci if ((flags & V4L2_FWHT_FL_PIXENC_MSK) != info->pixenc) 32162306a36Sopenharmony_ci return -EINVAL; 32262306a36Sopenharmony_ci components_num = 1 + ((flags & V4L2_FWHT_FL_COMPONENTS_NUM_MSK) >> 32362306a36Sopenharmony_ci V4L2_FWHT_FL_COMPONENTS_NUM_OFFSET); 32462306a36Sopenharmony_ci } 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci if (components_num != info->components_num) 32762306a36Sopenharmony_ci return -EINVAL; 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci state->colorspace = ntohl(state->header.colorspace); 33062306a36Sopenharmony_ci state->xfer_func = ntohl(state->header.xfer_func); 33162306a36Sopenharmony_ci state->ycbcr_enc = ntohl(state->header.ycbcr_enc); 33262306a36Sopenharmony_ci state->quantization = ntohl(state->header.quantization); 33362306a36Sopenharmony_ci cf.rlc_data = (__be16 *)p_in; 33462306a36Sopenharmony_ci cf.size = ntohl(state->header.size); 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci hdr_width_div = (flags & V4L2_FWHT_FL_CHROMA_FULL_WIDTH) ? 1 : 2; 33762306a36Sopenharmony_ci hdr_height_div = (flags & V4L2_FWHT_FL_CHROMA_FULL_HEIGHT) ? 1 : 2; 33862306a36Sopenharmony_ci if (hdr_width_div != info->width_div || 33962306a36Sopenharmony_ci hdr_height_div != info->height_div) 34062306a36Sopenharmony_ci return -EINVAL; 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci if (prepare_raw_frame(&dst_rf, info, p_out, dst_size)) 34362306a36Sopenharmony_ci return -EINVAL; 34462306a36Sopenharmony_ci if (info->planes_num == 3) { 34562306a36Sopenharmony_ci dst_chroma_stride /= 2; 34662306a36Sopenharmony_ci ref_chroma_stride /= 2; 34762306a36Sopenharmony_ci } 34862306a36Sopenharmony_ci if (info->id == V4L2_PIX_FMT_NV24 || 34962306a36Sopenharmony_ci info->id == V4L2_PIX_FMT_NV42) { 35062306a36Sopenharmony_ci dst_chroma_stride *= 2; 35162306a36Sopenharmony_ci ref_chroma_stride *= 2; 35262306a36Sopenharmony_ci } 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci ref_size = state->ref_stride * state->coded_height; 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci if (prepare_raw_frame(&state->ref_frame, info, state->ref_frame.buf, 35862306a36Sopenharmony_ci ref_size)) 35962306a36Sopenharmony_ci return -EINVAL; 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci if (!fwht_decode_frame(&cf, flags, components_num, 36262306a36Sopenharmony_ci state->visible_width, state->visible_height, 36362306a36Sopenharmony_ci &state->ref_frame, state->ref_stride, ref_chroma_stride, 36462306a36Sopenharmony_ci &dst_rf, state->stride, dst_chroma_stride)) 36562306a36Sopenharmony_ci return -EINVAL; 36662306a36Sopenharmony_ci return 0; 36762306a36Sopenharmony_ci} 368