368 lines · c
1// SPDX-License-Identifier: LGPL-2.12/*3 * A V4L2 frontend for the FWHT codec4 *5 * Copyright 2018 Cisco Systems, Inc. and/or its affiliates. All rights reserved.6 */7 8#include <linux/errno.h>9#include <linux/string.h>10#include <linux/videodev2.h>11#include "codec-v4l2-fwht.h"12 13static const struct v4l2_fwht_pixfmt_info v4l2_fwht_pixfmts[] = {14 { V4L2_PIX_FMT_YUV420, 1, 3, 2, 1, 1, 2, 2, 3, 3, V4L2_FWHT_FL_PIXENC_YUV},15 { V4L2_PIX_FMT_YVU420, 1, 3, 2, 1, 1, 2, 2, 3, 3, V4L2_FWHT_FL_PIXENC_YUV},16 { V4L2_PIX_FMT_YUV422P, 1, 2, 1, 1, 1, 2, 1, 3, 3, V4L2_FWHT_FL_PIXENC_YUV},17 { V4L2_PIX_FMT_NV12, 1, 3, 2, 1, 2, 2, 2, 3, 2, V4L2_FWHT_FL_PIXENC_YUV},18 { V4L2_PIX_FMT_NV21, 1, 3, 2, 1, 2, 2, 2, 3, 2, V4L2_FWHT_FL_PIXENC_YUV},19 { V4L2_PIX_FMT_NV16, 1, 2, 1, 1, 2, 2, 1, 3, 2, V4L2_FWHT_FL_PIXENC_YUV},20 { V4L2_PIX_FMT_NV61, 1, 2, 1, 1, 2, 2, 1, 3, 2, V4L2_FWHT_FL_PIXENC_YUV},21 { V4L2_PIX_FMT_NV24, 1, 3, 1, 1, 2, 1, 1, 3, 2, V4L2_FWHT_FL_PIXENC_YUV},22 { V4L2_PIX_FMT_NV42, 1, 3, 1, 1, 2, 1, 1, 3, 2, V4L2_FWHT_FL_PIXENC_YUV},23 { V4L2_PIX_FMT_YUYV, 2, 2, 1, 2, 4, 2, 1, 3, 1, V4L2_FWHT_FL_PIXENC_YUV},24 { V4L2_PIX_FMT_YVYU, 2, 2, 1, 2, 4, 2, 1, 3, 1, V4L2_FWHT_FL_PIXENC_YUV},25 { V4L2_PIX_FMT_UYVY, 2, 2, 1, 2, 4, 2, 1, 3, 1, V4L2_FWHT_FL_PIXENC_YUV},26 { V4L2_PIX_FMT_VYUY, 2, 2, 1, 2, 4, 2, 1, 3, 1, V4L2_FWHT_FL_PIXENC_YUV},27 { V4L2_PIX_FMT_BGR24, 3, 3, 1, 3, 3, 1, 1, 3, 1, V4L2_FWHT_FL_PIXENC_RGB},28 { V4L2_PIX_FMT_RGB24, 3, 3, 1, 3, 3, 1, 1, 3, 1, V4L2_FWHT_FL_PIXENC_RGB},29 { V4L2_PIX_FMT_HSV24, 3, 3, 1, 3, 3, 1, 1, 3, 1, V4L2_FWHT_FL_PIXENC_HSV},30 { V4L2_PIX_FMT_BGR32, 4, 4, 1, 4, 4, 1, 1, 4, 1, V4L2_FWHT_FL_PIXENC_RGB},31 { V4L2_PIX_FMT_XBGR32, 4, 4, 1, 4, 4, 1, 1, 4, 1, V4L2_FWHT_FL_PIXENC_RGB},32 { V4L2_PIX_FMT_ABGR32, 4, 4, 1, 4, 4, 1, 1, 4, 1, V4L2_FWHT_FL_PIXENC_RGB},33 { V4L2_PIX_FMT_RGB32, 4, 4, 1, 4, 4, 1, 1, 4, 1, V4L2_FWHT_FL_PIXENC_RGB},34 { V4L2_PIX_FMT_XRGB32, 4, 4, 1, 4, 4, 1, 1, 4, 1, V4L2_FWHT_FL_PIXENC_RGB},35 { V4L2_PIX_FMT_ARGB32, 4, 4, 1, 4, 4, 1, 1, 4, 1, V4L2_FWHT_FL_PIXENC_RGB},36 { V4L2_PIX_FMT_BGRX32, 4, 4, 1, 4, 4, 1, 1, 4, 1, V4L2_FWHT_FL_PIXENC_RGB},37 { V4L2_PIX_FMT_BGRA32, 4, 4, 1, 4, 4, 1, 1, 4, 1, V4L2_FWHT_FL_PIXENC_RGB},38 { V4L2_PIX_FMT_RGBX32, 4, 4, 1, 4, 4, 1, 1, 4, 1, V4L2_FWHT_FL_PIXENC_RGB},39 { V4L2_PIX_FMT_RGBA32, 4, 4, 1, 4, 4, 1, 1, 4, 1, V4L2_FWHT_FL_PIXENC_RGB},40 { V4L2_PIX_FMT_HSV32, 4, 4, 1, 4, 4, 1, 1, 4, 1, V4L2_FWHT_FL_PIXENC_HSV},41 { V4L2_PIX_FMT_GREY, 1, 1, 1, 1, 0, 1, 1, 1, 1, V4L2_FWHT_FL_PIXENC_RGB},42};43 44bool v4l2_fwht_validate_fmt(const struct v4l2_fwht_pixfmt_info *info,45 u32 width_div, u32 height_div, u32 components_num,46 u32 pixenc)47{48 if (info->width_div == width_div &&49 info->height_div == height_div &&50 (!pixenc || info->pixenc == pixenc) &&51 info->components_num == components_num)52 return true;53 return false;54}55 56const struct v4l2_fwht_pixfmt_info *v4l2_fwht_find_nth_fmt(u32 width_div,57 u32 height_div,58 u32 components_num,59 u32 pixenc,60 unsigned int start_idx)61{62 unsigned int i;63 64 for (i = 0; i < ARRAY_SIZE(v4l2_fwht_pixfmts); i++) {65 bool is_valid = v4l2_fwht_validate_fmt(&v4l2_fwht_pixfmts[i],66 width_div, height_div,67 components_num, pixenc);68 if (is_valid) {69 if (start_idx == 0)70 return v4l2_fwht_pixfmts + i;71 start_idx--;72 }73 }74 return NULL;75}76 77const struct v4l2_fwht_pixfmt_info *v4l2_fwht_find_pixfmt(u32 pixelformat)78{79 unsigned int i;80 81 for (i = 0; i < ARRAY_SIZE(v4l2_fwht_pixfmts); i++)82 if (v4l2_fwht_pixfmts[i].id == pixelformat)83 return v4l2_fwht_pixfmts + i;84 return NULL;85}86 87const struct v4l2_fwht_pixfmt_info *v4l2_fwht_get_pixfmt(u32 idx)88{89 if (idx >= ARRAY_SIZE(v4l2_fwht_pixfmts))90 return NULL;91 return v4l2_fwht_pixfmts + idx;92}93 94static int prepare_raw_frame(struct fwht_raw_frame *rf,95 const struct v4l2_fwht_pixfmt_info *info, u8 *buf,96 unsigned int size)97{98 rf->luma = buf;99 rf->width_div = info->width_div;100 rf->height_div = info->height_div;101 rf->luma_alpha_step = info->luma_alpha_step;102 rf->chroma_step = info->chroma_step;103 rf->alpha = NULL;104 rf->components_num = info->components_num;105 106 /*107 * The buffer is NULL if it is the reference108 * frame of an I-frame in the stateless decoder109 */110 if (!buf) {111 rf->luma = NULL;112 rf->cb = NULL;113 rf->cr = NULL;114 rf->alpha = NULL;115 return 0;116 }117 switch (info->id) {118 case V4L2_PIX_FMT_GREY:119 rf->cb = NULL;120 rf->cr = NULL;121 break;122 case V4L2_PIX_FMT_YUV420:123 rf->cb = rf->luma + size;124 rf->cr = rf->cb + size / 4;125 break;126 case V4L2_PIX_FMT_YVU420:127 rf->cr = rf->luma + size;128 rf->cb = rf->cr + size / 4;129 break;130 case V4L2_PIX_FMT_YUV422P:131 rf->cb = rf->luma + size;132 rf->cr = rf->cb + size / 2;133 break;134 case V4L2_PIX_FMT_NV12:135 case V4L2_PIX_FMT_NV16:136 case V4L2_PIX_FMT_NV24:137 rf->cb = rf->luma + size;138 rf->cr = rf->cb + 1;139 break;140 case V4L2_PIX_FMT_NV21:141 case V4L2_PIX_FMT_NV61:142 case V4L2_PIX_FMT_NV42:143 rf->cr = rf->luma + size;144 rf->cb = rf->cr + 1;145 break;146 case V4L2_PIX_FMT_YUYV:147 rf->cb = rf->luma + 1;148 rf->cr = rf->cb + 2;149 break;150 case V4L2_PIX_FMT_YVYU:151 rf->cr = rf->luma + 1;152 rf->cb = rf->cr + 2;153 break;154 case V4L2_PIX_FMT_UYVY:155 rf->cb = rf->luma;156 rf->cr = rf->cb + 2;157 rf->luma++;158 break;159 case V4L2_PIX_FMT_VYUY:160 rf->cr = rf->luma;161 rf->cb = rf->cr + 2;162 rf->luma++;163 break;164 case V4L2_PIX_FMT_RGB24:165 case V4L2_PIX_FMT_HSV24:166 rf->cr = rf->luma;167 rf->cb = rf->cr + 2;168 rf->luma++;169 break;170 case V4L2_PIX_FMT_BGR24:171 rf->cb = rf->luma;172 rf->cr = rf->cb + 2;173 rf->luma++;174 break;175 case V4L2_PIX_FMT_RGB32:176 case V4L2_PIX_FMT_XRGB32:177 case V4L2_PIX_FMT_HSV32:178 case V4L2_PIX_FMT_ARGB32:179 rf->alpha = rf->luma;180 rf->cr = rf->luma + 1;181 rf->cb = rf->cr + 2;182 rf->luma += 2;183 break;184 case V4L2_PIX_FMT_BGR32:185 case V4L2_PIX_FMT_XBGR32:186 case V4L2_PIX_FMT_ABGR32:187 rf->cb = rf->luma;188 rf->cr = rf->cb + 2;189 rf->luma++;190 rf->alpha = rf->cr + 1;191 break;192 case V4L2_PIX_FMT_BGRX32:193 case V4L2_PIX_FMT_BGRA32:194 rf->alpha = rf->luma;195 rf->cb = rf->luma + 1;196 rf->cr = rf->cb + 2;197 rf->luma += 2;198 break;199 case V4L2_PIX_FMT_RGBX32:200 case V4L2_PIX_FMT_RGBA32:201 rf->alpha = rf->luma + 3;202 rf->cr = rf->luma;203 rf->cb = rf->cr + 2;204 rf->luma++;205 break;206 default:207 return -EINVAL;208 }209 return 0;210}211 212int v4l2_fwht_encode(struct v4l2_fwht_state *state, u8 *p_in, u8 *p_out)213{214 unsigned int size = state->stride * state->coded_height;215 unsigned int chroma_stride = state->stride;216 const struct v4l2_fwht_pixfmt_info *info = state->info;217 struct fwht_cframe_hdr *p_hdr;218 struct fwht_cframe cf;219 struct fwht_raw_frame rf;220 u32 encoding;221 u32 flags = 0;222 223 if (!info)224 return -EINVAL;225 226 if (prepare_raw_frame(&rf, info, p_in, size))227 return -EINVAL;228 229 if (info->planes_num == 3)230 chroma_stride /= 2;231 232 if (info->id == V4L2_PIX_FMT_NV24 ||233 info->id == V4L2_PIX_FMT_NV42)234 chroma_stride *= 2;235 236 cf.i_frame_qp = state->i_frame_qp;237 cf.p_frame_qp = state->p_frame_qp;238 cf.rlc_data = (__be16 *)(p_out + sizeof(*p_hdr));239 240 encoding = fwht_encode_frame(&rf, &state->ref_frame, &cf,241 !state->gop_cnt,242 state->gop_cnt == state->gop_size - 1,243 state->visible_width,244 state->visible_height,245 state->stride, chroma_stride);246 if (!(encoding & FWHT_FRAME_PCODED))247 state->gop_cnt = 0;248 if (++state->gop_cnt >= state->gop_size)249 state->gop_cnt = 0;250 251 p_hdr = (struct fwht_cframe_hdr *)p_out;252 p_hdr->magic1 = FWHT_MAGIC1;253 p_hdr->magic2 = FWHT_MAGIC2;254 p_hdr->version = htonl(V4L2_FWHT_VERSION);255 p_hdr->width = htonl(state->visible_width);256 p_hdr->height = htonl(state->visible_height);257 flags |= (info->components_num - 1) << V4L2_FWHT_FL_COMPONENTS_NUM_OFFSET;258 flags |= info->pixenc;259 if (encoding & FWHT_LUMA_UNENCODED)260 flags |= V4L2_FWHT_FL_LUMA_IS_UNCOMPRESSED;261 if (encoding & FWHT_CB_UNENCODED)262 flags |= V4L2_FWHT_FL_CB_IS_UNCOMPRESSED;263 if (encoding & FWHT_CR_UNENCODED)264 flags |= V4L2_FWHT_FL_CR_IS_UNCOMPRESSED;265 if (encoding & FWHT_ALPHA_UNENCODED)266 flags |= V4L2_FWHT_FL_ALPHA_IS_UNCOMPRESSED;267 if (!(encoding & FWHT_FRAME_PCODED))268 flags |= V4L2_FWHT_FL_I_FRAME;269 if (rf.height_div == 1)270 flags |= V4L2_FWHT_FL_CHROMA_FULL_HEIGHT;271 if (rf.width_div == 1)272 flags |= V4L2_FWHT_FL_CHROMA_FULL_WIDTH;273 p_hdr->flags = htonl(flags);274 p_hdr->colorspace = htonl(state->colorspace);275 p_hdr->xfer_func = htonl(state->xfer_func);276 p_hdr->ycbcr_enc = htonl(state->ycbcr_enc);277 p_hdr->quantization = htonl(state->quantization);278 p_hdr->size = htonl(cf.size);279 return cf.size + sizeof(*p_hdr);280}281 282int v4l2_fwht_decode(struct v4l2_fwht_state *state, u8 *p_in, u8 *p_out)283{284 u32 flags;285 struct fwht_cframe cf;286 unsigned int components_num = 3;287 unsigned int version;288 const struct v4l2_fwht_pixfmt_info *info;289 unsigned int hdr_width_div, hdr_height_div;290 struct fwht_raw_frame dst_rf;291 unsigned int dst_chroma_stride = state->stride;292 unsigned int ref_chroma_stride = state->ref_stride;293 unsigned int dst_size = state->stride * state->coded_height;294 unsigned int ref_size;295 296 if (!state->info)297 return -EINVAL;298 299 info = state->info;300 301 version = ntohl(state->header.version);302 if (!version || version > V4L2_FWHT_VERSION) {303 pr_err("version %d is not supported, current version is %d\n",304 version, V4L2_FWHT_VERSION);305 return -EINVAL;306 }307 308 if (state->header.magic1 != FWHT_MAGIC1 ||309 state->header.magic2 != FWHT_MAGIC2)310 return -EINVAL;311 312 /* TODO: support resolution changes */313 if (ntohl(state->header.width) != state->visible_width ||314 ntohl(state->header.height) != state->visible_height)315 return -EINVAL;316 317 flags = ntohl(state->header.flags);318 319 if (version >= 2) {320 if ((flags & V4L2_FWHT_FL_PIXENC_MSK) != info->pixenc)321 return -EINVAL;322 components_num = 1 + ((flags & V4L2_FWHT_FL_COMPONENTS_NUM_MSK) >>323 V4L2_FWHT_FL_COMPONENTS_NUM_OFFSET);324 }325 326 if (components_num != info->components_num)327 return -EINVAL;328 329 state->colorspace = ntohl(state->header.colorspace);330 state->xfer_func = ntohl(state->header.xfer_func);331 state->ycbcr_enc = ntohl(state->header.ycbcr_enc);332 state->quantization = ntohl(state->header.quantization);333 cf.rlc_data = (__be16 *)p_in;334 cf.size = ntohl(state->header.size);335 336 hdr_width_div = (flags & V4L2_FWHT_FL_CHROMA_FULL_WIDTH) ? 1 : 2;337 hdr_height_div = (flags & V4L2_FWHT_FL_CHROMA_FULL_HEIGHT) ? 1 : 2;338 if (hdr_width_div != info->width_div ||339 hdr_height_div != info->height_div)340 return -EINVAL;341 342 if (prepare_raw_frame(&dst_rf, info, p_out, dst_size))343 return -EINVAL;344 if (info->planes_num == 3) {345 dst_chroma_stride /= 2;346 ref_chroma_stride /= 2;347 }348 if (info->id == V4L2_PIX_FMT_NV24 ||349 info->id == V4L2_PIX_FMT_NV42) {350 dst_chroma_stride *= 2;351 ref_chroma_stride *= 2;352 }353 354 355 ref_size = state->ref_stride * state->coded_height;356 357 if (prepare_raw_frame(&state->ref_frame, info, state->ref_frame.buf,358 ref_size))359 return -EINVAL;360 361 if (!fwht_decode_frame(&cf, flags, components_num,362 state->visible_width, state->visible_height,363 &state->ref_frame, state->ref_stride, ref_chroma_stride,364 &dst_rf, state->stride, dst_chroma_stride))365 return -EINVAL;366 return 0;367}368