brintos

brintos / linux-shallow public Read only

0
0
Text · 10.8 KiB · 0c83678 Raw
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