18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: LGPL-2.1 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * A V4L2 frontend for the FWHT codec 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright 2018 Cisco Systems, Inc. and/or its affiliates. All rights reserved. 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/errno.h> 98c2ecf20Sopenharmony_ci#include <linux/string.h> 108c2ecf20Sopenharmony_ci#include <linux/videodev2.h> 118c2ecf20Sopenharmony_ci#include "codec-v4l2-fwht.h" 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_cistatic const struct v4l2_fwht_pixfmt_info v4l2_fwht_pixfmts[] = { 148c2ecf20Sopenharmony_ci { V4L2_PIX_FMT_YUV420, 1, 3, 2, 1, 1, 2, 2, 3, 3, FWHT_FL_PIXENC_YUV}, 158c2ecf20Sopenharmony_ci { V4L2_PIX_FMT_YVU420, 1, 3, 2, 1, 1, 2, 2, 3, 3, FWHT_FL_PIXENC_YUV}, 168c2ecf20Sopenharmony_ci { V4L2_PIX_FMT_YUV422P, 1, 2, 1, 1, 1, 2, 1, 3, 3, FWHT_FL_PIXENC_YUV}, 178c2ecf20Sopenharmony_ci { V4L2_PIX_FMT_NV12, 1, 3, 2, 1, 2, 2, 2, 3, 2, FWHT_FL_PIXENC_YUV}, 188c2ecf20Sopenharmony_ci { V4L2_PIX_FMT_NV21, 1, 3, 2, 1, 2, 2, 2, 3, 2, FWHT_FL_PIXENC_YUV}, 198c2ecf20Sopenharmony_ci { V4L2_PIX_FMT_NV16, 1, 2, 1, 1, 2, 2, 1, 3, 2, FWHT_FL_PIXENC_YUV}, 208c2ecf20Sopenharmony_ci { V4L2_PIX_FMT_NV61, 1, 2, 1, 1, 2, 2, 1, 3, 2, FWHT_FL_PIXENC_YUV}, 218c2ecf20Sopenharmony_ci { V4L2_PIX_FMT_NV24, 1, 3, 1, 1, 2, 1, 1, 3, 2, FWHT_FL_PIXENC_YUV}, 228c2ecf20Sopenharmony_ci { V4L2_PIX_FMT_NV42, 1, 3, 1, 1, 2, 1, 1, 3, 2, FWHT_FL_PIXENC_YUV}, 238c2ecf20Sopenharmony_ci { V4L2_PIX_FMT_YUYV, 2, 2, 1, 2, 4, 2, 1, 3, 1, FWHT_FL_PIXENC_YUV}, 248c2ecf20Sopenharmony_ci { V4L2_PIX_FMT_YVYU, 2, 2, 1, 2, 4, 2, 1, 3, 1, FWHT_FL_PIXENC_YUV}, 258c2ecf20Sopenharmony_ci { V4L2_PIX_FMT_UYVY, 2, 2, 1, 2, 4, 2, 1, 3, 1, FWHT_FL_PIXENC_YUV}, 268c2ecf20Sopenharmony_ci { V4L2_PIX_FMT_VYUY, 2, 2, 1, 2, 4, 2, 1, 3, 1, FWHT_FL_PIXENC_YUV}, 278c2ecf20Sopenharmony_ci { V4L2_PIX_FMT_BGR24, 3, 3, 1, 3, 3, 1, 1, 3, 1, FWHT_FL_PIXENC_RGB}, 288c2ecf20Sopenharmony_ci { V4L2_PIX_FMT_RGB24, 3, 3, 1, 3, 3, 1, 1, 3, 1, FWHT_FL_PIXENC_RGB}, 298c2ecf20Sopenharmony_ci { V4L2_PIX_FMT_HSV24, 3, 3, 1, 3, 3, 1, 1, 3, 1, FWHT_FL_PIXENC_HSV}, 308c2ecf20Sopenharmony_ci { V4L2_PIX_FMT_BGR32, 4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_RGB}, 318c2ecf20Sopenharmony_ci { V4L2_PIX_FMT_XBGR32, 4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_RGB}, 328c2ecf20Sopenharmony_ci { V4L2_PIX_FMT_ABGR32, 4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_RGB}, 338c2ecf20Sopenharmony_ci { V4L2_PIX_FMT_RGB32, 4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_RGB}, 348c2ecf20Sopenharmony_ci { V4L2_PIX_FMT_XRGB32, 4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_RGB}, 358c2ecf20Sopenharmony_ci { V4L2_PIX_FMT_ARGB32, 4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_RGB}, 368c2ecf20Sopenharmony_ci { V4L2_PIX_FMT_BGRX32, 4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_RGB}, 378c2ecf20Sopenharmony_ci { V4L2_PIX_FMT_BGRA32, 4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_RGB}, 388c2ecf20Sopenharmony_ci { V4L2_PIX_FMT_RGBX32, 4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_RGB}, 398c2ecf20Sopenharmony_ci { V4L2_PIX_FMT_RGBA32, 4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_RGB}, 408c2ecf20Sopenharmony_ci { V4L2_PIX_FMT_HSV32, 4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_HSV}, 418c2ecf20Sopenharmony_ci { V4L2_PIX_FMT_GREY, 1, 1, 1, 1, 0, 1, 1, 1, 1, FWHT_FL_PIXENC_RGB}, 428c2ecf20Sopenharmony_ci}; 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_cibool v4l2_fwht_validate_fmt(const struct v4l2_fwht_pixfmt_info *info, 458c2ecf20Sopenharmony_ci u32 width_div, u32 height_div, u32 components_num, 468c2ecf20Sopenharmony_ci u32 pixenc) 478c2ecf20Sopenharmony_ci{ 488c2ecf20Sopenharmony_ci if (info->width_div == width_div && 498c2ecf20Sopenharmony_ci info->height_div == height_div && 508c2ecf20Sopenharmony_ci (!pixenc || info->pixenc == pixenc) && 518c2ecf20Sopenharmony_ci info->components_num == components_num) 528c2ecf20Sopenharmony_ci return true; 538c2ecf20Sopenharmony_ci return false; 548c2ecf20Sopenharmony_ci} 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ciconst struct v4l2_fwht_pixfmt_info *v4l2_fwht_find_nth_fmt(u32 width_div, 578c2ecf20Sopenharmony_ci u32 height_div, 588c2ecf20Sopenharmony_ci u32 components_num, 598c2ecf20Sopenharmony_ci u32 pixenc, 608c2ecf20Sopenharmony_ci unsigned int start_idx) 618c2ecf20Sopenharmony_ci{ 628c2ecf20Sopenharmony_ci unsigned int i; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(v4l2_fwht_pixfmts); i++) { 658c2ecf20Sopenharmony_ci bool is_valid = v4l2_fwht_validate_fmt(&v4l2_fwht_pixfmts[i], 668c2ecf20Sopenharmony_ci width_div, height_div, 678c2ecf20Sopenharmony_ci components_num, pixenc); 688c2ecf20Sopenharmony_ci if (is_valid) { 698c2ecf20Sopenharmony_ci if (start_idx == 0) 708c2ecf20Sopenharmony_ci return v4l2_fwht_pixfmts + i; 718c2ecf20Sopenharmony_ci start_idx--; 728c2ecf20Sopenharmony_ci } 738c2ecf20Sopenharmony_ci } 748c2ecf20Sopenharmony_ci return NULL; 758c2ecf20Sopenharmony_ci} 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ciconst struct v4l2_fwht_pixfmt_info *v4l2_fwht_find_pixfmt(u32 pixelformat) 788c2ecf20Sopenharmony_ci{ 798c2ecf20Sopenharmony_ci unsigned int i; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(v4l2_fwht_pixfmts); i++) 828c2ecf20Sopenharmony_ci if (v4l2_fwht_pixfmts[i].id == pixelformat) 838c2ecf20Sopenharmony_ci return v4l2_fwht_pixfmts + i; 848c2ecf20Sopenharmony_ci return NULL; 858c2ecf20Sopenharmony_ci} 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ciconst struct v4l2_fwht_pixfmt_info *v4l2_fwht_get_pixfmt(u32 idx) 888c2ecf20Sopenharmony_ci{ 898c2ecf20Sopenharmony_ci if (idx >= ARRAY_SIZE(v4l2_fwht_pixfmts)) 908c2ecf20Sopenharmony_ci return NULL; 918c2ecf20Sopenharmony_ci return v4l2_fwht_pixfmts + idx; 928c2ecf20Sopenharmony_ci} 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_cistatic int prepare_raw_frame(struct fwht_raw_frame *rf, 958c2ecf20Sopenharmony_ci const struct v4l2_fwht_pixfmt_info *info, u8 *buf, 968c2ecf20Sopenharmony_ci unsigned int size) 978c2ecf20Sopenharmony_ci{ 988c2ecf20Sopenharmony_ci rf->luma = buf; 998c2ecf20Sopenharmony_ci rf->width_div = info->width_div; 1008c2ecf20Sopenharmony_ci rf->height_div = info->height_div; 1018c2ecf20Sopenharmony_ci rf->luma_alpha_step = info->luma_alpha_step; 1028c2ecf20Sopenharmony_ci rf->chroma_step = info->chroma_step; 1038c2ecf20Sopenharmony_ci rf->alpha = NULL; 1048c2ecf20Sopenharmony_ci rf->components_num = info->components_num; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci /* 1078c2ecf20Sopenharmony_ci * The buffer is NULL if it is the reference 1088c2ecf20Sopenharmony_ci * frame of an I-frame in the stateless decoder 1098c2ecf20Sopenharmony_ci */ 1108c2ecf20Sopenharmony_ci if (!buf) { 1118c2ecf20Sopenharmony_ci rf->luma = NULL; 1128c2ecf20Sopenharmony_ci rf->cb = NULL; 1138c2ecf20Sopenharmony_ci rf->cr = NULL; 1148c2ecf20Sopenharmony_ci rf->alpha = NULL; 1158c2ecf20Sopenharmony_ci return 0; 1168c2ecf20Sopenharmony_ci } 1178c2ecf20Sopenharmony_ci switch (info->id) { 1188c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_GREY: 1198c2ecf20Sopenharmony_ci rf->cb = NULL; 1208c2ecf20Sopenharmony_ci rf->cr = NULL; 1218c2ecf20Sopenharmony_ci break; 1228c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_YUV420: 1238c2ecf20Sopenharmony_ci rf->cb = rf->luma + size; 1248c2ecf20Sopenharmony_ci rf->cr = rf->cb + size / 4; 1258c2ecf20Sopenharmony_ci break; 1268c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_YVU420: 1278c2ecf20Sopenharmony_ci rf->cr = rf->luma + size; 1288c2ecf20Sopenharmony_ci rf->cb = rf->cr + size / 4; 1298c2ecf20Sopenharmony_ci break; 1308c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_YUV422P: 1318c2ecf20Sopenharmony_ci rf->cb = rf->luma + size; 1328c2ecf20Sopenharmony_ci rf->cr = rf->cb + size / 2; 1338c2ecf20Sopenharmony_ci break; 1348c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_NV12: 1358c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_NV16: 1368c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_NV24: 1378c2ecf20Sopenharmony_ci rf->cb = rf->luma + size; 1388c2ecf20Sopenharmony_ci rf->cr = rf->cb + 1; 1398c2ecf20Sopenharmony_ci break; 1408c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_NV21: 1418c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_NV61: 1428c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_NV42: 1438c2ecf20Sopenharmony_ci rf->cr = rf->luma + size; 1448c2ecf20Sopenharmony_ci rf->cb = rf->cr + 1; 1458c2ecf20Sopenharmony_ci break; 1468c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_YUYV: 1478c2ecf20Sopenharmony_ci rf->cb = rf->luma + 1; 1488c2ecf20Sopenharmony_ci rf->cr = rf->cb + 2; 1498c2ecf20Sopenharmony_ci break; 1508c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_YVYU: 1518c2ecf20Sopenharmony_ci rf->cr = rf->luma + 1; 1528c2ecf20Sopenharmony_ci rf->cb = rf->cr + 2; 1538c2ecf20Sopenharmony_ci break; 1548c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_UYVY: 1558c2ecf20Sopenharmony_ci rf->cb = rf->luma; 1568c2ecf20Sopenharmony_ci rf->cr = rf->cb + 2; 1578c2ecf20Sopenharmony_ci rf->luma++; 1588c2ecf20Sopenharmony_ci break; 1598c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_VYUY: 1608c2ecf20Sopenharmony_ci rf->cr = rf->luma; 1618c2ecf20Sopenharmony_ci rf->cb = rf->cr + 2; 1628c2ecf20Sopenharmony_ci rf->luma++; 1638c2ecf20Sopenharmony_ci break; 1648c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_RGB24: 1658c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_HSV24: 1668c2ecf20Sopenharmony_ci rf->cr = rf->luma; 1678c2ecf20Sopenharmony_ci rf->cb = rf->cr + 2; 1688c2ecf20Sopenharmony_ci rf->luma++; 1698c2ecf20Sopenharmony_ci break; 1708c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_BGR24: 1718c2ecf20Sopenharmony_ci rf->cb = rf->luma; 1728c2ecf20Sopenharmony_ci rf->cr = rf->cb + 2; 1738c2ecf20Sopenharmony_ci rf->luma++; 1748c2ecf20Sopenharmony_ci break; 1758c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_RGB32: 1768c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_XRGB32: 1778c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_HSV32: 1788c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_ARGB32: 1798c2ecf20Sopenharmony_ci rf->alpha = rf->luma; 1808c2ecf20Sopenharmony_ci rf->cr = rf->luma + 1; 1818c2ecf20Sopenharmony_ci rf->cb = rf->cr + 2; 1828c2ecf20Sopenharmony_ci rf->luma += 2; 1838c2ecf20Sopenharmony_ci break; 1848c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_BGR32: 1858c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_XBGR32: 1868c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_ABGR32: 1878c2ecf20Sopenharmony_ci rf->cb = rf->luma; 1888c2ecf20Sopenharmony_ci rf->cr = rf->cb + 2; 1898c2ecf20Sopenharmony_ci rf->luma++; 1908c2ecf20Sopenharmony_ci rf->alpha = rf->cr + 1; 1918c2ecf20Sopenharmony_ci break; 1928c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_BGRX32: 1938c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_BGRA32: 1948c2ecf20Sopenharmony_ci rf->alpha = rf->luma; 1958c2ecf20Sopenharmony_ci rf->cb = rf->luma + 1; 1968c2ecf20Sopenharmony_ci rf->cr = rf->cb + 2; 1978c2ecf20Sopenharmony_ci rf->luma += 2; 1988c2ecf20Sopenharmony_ci break; 1998c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_RGBX32: 2008c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_RGBA32: 2018c2ecf20Sopenharmony_ci rf->alpha = rf->luma + 3; 2028c2ecf20Sopenharmony_ci rf->cr = rf->luma; 2038c2ecf20Sopenharmony_ci rf->cb = rf->cr + 2; 2048c2ecf20Sopenharmony_ci rf->luma++; 2058c2ecf20Sopenharmony_ci break; 2068c2ecf20Sopenharmony_ci default: 2078c2ecf20Sopenharmony_ci return -EINVAL; 2088c2ecf20Sopenharmony_ci } 2098c2ecf20Sopenharmony_ci return 0; 2108c2ecf20Sopenharmony_ci} 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ciint v4l2_fwht_encode(struct v4l2_fwht_state *state, u8 *p_in, u8 *p_out) 2138c2ecf20Sopenharmony_ci{ 2148c2ecf20Sopenharmony_ci unsigned int size = state->stride * state->coded_height; 2158c2ecf20Sopenharmony_ci unsigned int chroma_stride = state->stride; 2168c2ecf20Sopenharmony_ci const struct v4l2_fwht_pixfmt_info *info = state->info; 2178c2ecf20Sopenharmony_ci struct fwht_cframe_hdr *p_hdr; 2188c2ecf20Sopenharmony_ci struct fwht_cframe cf; 2198c2ecf20Sopenharmony_ci struct fwht_raw_frame rf; 2208c2ecf20Sopenharmony_ci u32 encoding; 2218c2ecf20Sopenharmony_ci u32 flags = 0; 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci if (!info) 2248c2ecf20Sopenharmony_ci return -EINVAL; 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci if (prepare_raw_frame(&rf, info, p_in, size)) 2278c2ecf20Sopenharmony_ci return -EINVAL; 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci if (info->planes_num == 3) 2308c2ecf20Sopenharmony_ci chroma_stride /= 2; 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci if (info->id == V4L2_PIX_FMT_NV24 || 2338c2ecf20Sopenharmony_ci info->id == V4L2_PIX_FMT_NV42) 2348c2ecf20Sopenharmony_ci chroma_stride *= 2; 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci cf.i_frame_qp = state->i_frame_qp; 2378c2ecf20Sopenharmony_ci cf.p_frame_qp = state->p_frame_qp; 2388c2ecf20Sopenharmony_ci cf.rlc_data = (__be16 *)(p_out + sizeof(*p_hdr)); 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci encoding = fwht_encode_frame(&rf, &state->ref_frame, &cf, 2418c2ecf20Sopenharmony_ci !state->gop_cnt, 2428c2ecf20Sopenharmony_ci state->gop_cnt == state->gop_size - 1, 2438c2ecf20Sopenharmony_ci state->visible_width, 2448c2ecf20Sopenharmony_ci state->visible_height, 2458c2ecf20Sopenharmony_ci state->stride, chroma_stride); 2468c2ecf20Sopenharmony_ci if (!(encoding & FWHT_FRAME_PCODED)) 2478c2ecf20Sopenharmony_ci state->gop_cnt = 0; 2488c2ecf20Sopenharmony_ci if (++state->gop_cnt >= state->gop_size) 2498c2ecf20Sopenharmony_ci state->gop_cnt = 0; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci p_hdr = (struct fwht_cframe_hdr *)p_out; 2528c2ecf20Sopenharmony_ci p_hdr->magic1 = FWHT_MAGIC1; 2538c2ecf20Sopenharmony_ci p_hdr->magic2 = FWHT_MAGIC2; 2548c2ecf20Sopenharmony_ci p_hdr->version = htonl(FWHT_VERSION); 2558c2ecf20Sopenharmony_ci p_hdr->width = htonl(state->visible_width); 2568c2ecf20Sopenharmony_ci p_hdr->height = htonl(state->visible_height); 2578c2ecf20Sopenharmony_ci flags |= (info->components_num - 1) << FWHT_FL_COMPONENTS_NUM_OFFSET; 2588c2ecf20Sopenharmony_ci flags |= info->pixenc; 2598c2ecf20Sopenharmony_ci if (encoding & FWHT_LUMA_UNENCODED) 2608c2ecf20Sopenharmony_ci flags |= FWHT_FL_LUMA_IS_UNCOMPRESSED; 2618c2ecf20Sopenharmony_ci if (encoding & FWHT_CB_UNENCODED) 2628c2ecf20Sopenharmony_ci flags |= FWHT_FL_CB_IS_UNCOMPRESSED; 2638c2ecf20Sopenharmony_ci if (encoding & FWHT_CR_UNENCODED) 2648c2ecf20Sopenharmony_ci flags |= FWHT_FL_CR_IS_UNCOMPRESSED; 2658c2ecf20Sopenharmony_ci if (encoding & FWHT_ALPHA_UNENCODED) 2668c2ecf20Sopenharmony_ci flags |= FWHT_FL_ALPHA_IS_UNCOMPRESSED; 2678c2ecf20Sopenharmony_ci if (!(encoding & FWHT_FRAME_PCODED)) 2688c2ecf20Sopenharmony_ci flags |= FWHT_FL_I_FRAME; 2698c2ecf20Sopenharmony_ci if (rf.height_div == 1) 2708c2ecf20Sopenharmony_ci flags |= FWHT_FL_CHROMA_FULL_HEIGHT; 2718c2ecf20Sopenharmony_ci if (rf.width_div == 1) 2728c2ecf20Sopenharmony_ci flags |= FWHT_FL_CHROMA_FULL_WIDTH; 2738c2ecf20Sopenharmony_ci p_hdr->flags = htonl(flags); 2748c2ecf20Sopenharmony_ci p_hdr->colorspace = htonl(state->colorspace); 2758c2ecf20Sopenharmony_ci p_hdr->xfer_func = htonl(state->xfer_func); 2768c2ecf20Sopenharmony_ci p_hdr->ycbcr_enc = htonl(state->ycbcr_enc); 2778c2ecf20Sopenharmony_ci p_hdr->quantization = htonl(state->quantization); 2788c2ecf20Sopenharmony_ci p_hdr->size = htonl(cf.size); 2798c2ecf20Sopenharmony_ci return cf.size + sizeof(*p_hdr); 2808c2ecf20Sopenharmony_ci} 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ciint v4l2_fwht_decode(struct v4l2_fwht_state *state, u8 *p_in, u8 *p_out) 2838c2ecf20Sopenharmony_ci{ 2848c2ecf20Sopenharmony_ci u32 flags; 2858c2ecf20Sopenharmony_ci struct fwht_cframe cf; 2868c2ecf20Sopenharmony_ci unsigned int components_num = 3; 2878c2ecf20Sopenharmony_ci unsigned int version; 2888c2ecf20Sopenharmony_ci const struct v4l2_fwht_pixfmt_info *info; 2898c2ecf20Sopenharmony_ci unsigned int hdr_width_div, hdr_height_div; 2908c2ecf20Sopenharmony_ci struct fwht_raw_frame dst_rf; 2918c2ecf20Sopenharmony_ci unsigned int dst_chroma_stride = state->stride; 2928c2ecf20Sopenharmony_ci unsigned int ref_chroma_stride = state->ref_stride; 2938c2ecf20Sopenharmony_ci unsigned int dst_size = state->stride * state->coded_height; 2948c2ecf20Sopenharmony_ci unsigned int ref_size; 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci if (!state->info) 2978c2ecf20Sopenharmony_ci return -EINVAL; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci info = state->info; 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci version = ntohl(state->header.version); 3028c2ecf20Sopenharmony_ci if (!version || version > FWHT_VERSION) { 3038c2ecf20Sopenharmony_ci pr_err("version %d is not supported, current version is %d\n", 3048c2ecf20Sopenharmony_ci version, FWHT_VERSION); 3058c2ecf20Sopenharmony_ci return -EINVAL; 3068c2ecf20Sopenharmony_ci } 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci if (state->header.magic1 != FWHT_MAGIC1 || 3098c2ecf20Sopenharmony_ci state->header.magic2 != FWHT_MAGIC2) 3108c2ecf20Sopenharmony_ci return -EINVAL; 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci /* TODO: support resolution changes */ 3138c2ecf20Sopenharmony_ci if (ntohl(state->header.width) != state->visible_width || 3148c2ecf20Sopenharmony_ci ntohl(state->header.height) != state->visible_height) 3158c2ecf20Sopenharmony_ci return -EINVAL; 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci flags = ntohl(state->header.flags); 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci if (version >= 2) { 3208c2ecf20Sopenharmony_ci if ((flags & FWHT_FL_PIXENC_MSK) != info->pixenc) 3218c2ecf20Sopenharmony_ci return -EINVAL; 3228c2ecf20Sopenharmony_ci components_num = 1 + ((flags & FWHT_FL_COMPONENTS_NUM_MSK) >> 3238c2ecf20Sopenharmony_ci FWHT_FL_COMPONENTS_NUM_OFFSET); 3248c2ecf20Sopenharmony_ci } 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci if (components_num != info->components_num) 3278c2ecf20Sopenharmony_ci return -EINVAL; 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci state->colorspace = ntohl(state->header.colorspace); 3308c2ecf20Sopenharmony_ci state->xfer_func = ntohl(state->header.xfer_func); 3318c2ecf20Sopenharmony_ci state->ycbcr_enc = ntohl(state->header.ycbcr_enc); 3328c2ecf20Sopenharmony_ci state->quantization = ntohl(state->header.quantization); 3338c2ecf20Sopenharmony_ci cf.rlc_data = (__be16 *)p_in; 3348c2ecf20Sopenharmony_ci cf.size = ntohl(state->header.size); 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci hdr_width_div = (flags & FWHT_FL_CHROMA_FULL_WIDTH) ? 1 : 2; 3378c2ecf20Sopenharmony_ci hdr_height_div = (flags & FWHT_FL_CHROMA_FULL_HEIGHT) ? 1 : 2; 3388c2ecf20Sopenharmony_ci if (hdr_width_div != info->width_div || 3398c2ecf20Sopenharmony_ci hdr_height_div != info->height_div) 3408c2ecf20Sopenharmony_ci return -EINVAL; 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci if (prepare_raw_frame(&dst_rf, info, p_out, dst_size)) 3438c2ecf20Sopenharmony_ci return -EINVAL; 3448c2ecf20Sopenharmony_ci if (info->planes_num == 3) { 3458c2ecf20Sopenharmony_ci dst_chroma_stride /= 2; 3468c2ecf20Sopenharmony_ci ref_chroma_stride /= 2; 3478c2ecf20Sopenharmony_ci } 3488c2ecf20Sopenharmony_ci if (info->id == V4L2_PIX_FMT_NV24 || 3498c2ecf20Sopenharmony_ci info->id == V4L2_PIX_FMT_NV42) { 3508c2ecf20Sopenharmony_ci dst_chroma_stride *= 2; 3518c2ecf20Sopenharmony_ci ref_chroma_stride *= 2; 3528c2ecf20Sopenharmony_ci } 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci ref_size = state->ref_stride * state->coded_height; 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci if (prepare_raw_frame(&state->ref_frame, info, state->ref_frame.buf, 3588c2ecf20Sopenharmony_ci ref_size)) 3598c2ecf20Sopenharmony_ci return -EINVAL; 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci if (!fwht_decode_frame(&cf, flags, components_num, 3628c2ecf20Sopenharmony_ci state->visible_width, state->visible_height, 3638c2ecf20Sopenharmony_ci &state->ref_frame, state->ref_stride, ref_chroma_stride, 3648c2ecf20Sopenharmony_ci &dst_rf, state->stride, dst_chroma_stride)) 3658c2ecf20Sopenharmony_ci return -EINVAL; 3668c2ecf20Sopenharmony_ci return 0; 3678c2ecf20Sopenharmony_ci} 368