0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/errno.h>
0009 #include <linux/string.h>
0010 #include <linux/videodev2.h>
0011 #include "codec-v4l2-fwht.h"
0012
0013 static const struct v4l2_fwht_pixfmt_info v4l2_fwht_pixfmts[] = {
0014 { V4L2_PIX_FMT_YUV420, 1, 3, 2, 1, 1, 2, 2, 3, 3, V4L2_FWHT_FL_PIXENC_YUV},
0015 { V4L2_PIX_FMT_YVU420, 1, 3, 2, 1, 1, 2, 2, 3, 3, V4L2_FWHT_FL_PIXENC_YUV},
0016 { V4L2_PIX_FMT_YUV422P, 1, 2, 1, 1, 1, 2, 1, 3, 3, V4L2_FWHT_FL_PIXENC_YUV},
0017 { V4L2_PIX_FMT_NV12, 1, 3, 2, 1, 2, 2, 2, 3, 2, V4L2_FWHT_FL_PIXENC_YUV},
0018 { V4L2_PIX_FMT_NV21, 1, 3, 2, 1, 2, 2, 2, 3, 2, V4L2_FWHT_FL_PIXENC_YUV},
0019 { V4L2_PIX_FMT_NV16, 1, 2, 1, 1, 2, 2, 1, 3, 2, V4L2_FWHT_FL_PIXENC_YUV},
0020 { V4L2_PIX_FMT_NV61, 1, 2, 1, 1, 2, 2, 1, 3, 2, V4L2_FWHT_FL_PIXENC_YUV},
0021 { V4L2_PIX_FMT_NV24, 1, 3, 1, 1, 2, 1, 1, 3, 2, V4L2_FWHT_FL_PIXENC_YUV},
0022 { V4L2_PIX_FMT_NV42, 1, 3, 1, 1, 2, 1, 1, 3, 2, V4L2_FWHT_FL_PIXENC_YUV},
0023 { V4L2_PIX_FMT_YUYV, 2, 2, 1, 2, 4, 2, 1, 3, 1, V4L2_FWHT_FL_PIXENC_YUV},
0024 { V4L2_PIX_FMT_YVYU, 2, 2, 1, 2, 4, 2, 1, 3, 1, V4L2_FWHT_FL_PIXENC_YUV},
0025 { V4L2_PIX_FMT_UYVY, 2, 2, 1, 2, 4, 2, 1, 3, 1, V4L2_FWHT_FL_PIXENC_YUV},
0026 { V4L2_PIX_FMT_VYUY, 2, 2, 1, 2, 4, 2, 1, 3, 1, V4L2_FWHT_FL_PIXENC_YUV},
0027 { V4L2_PIX_FMT_BGR24, 3, 3, 1, 3, 3, 1, 1, 3, 1, V4L2_FWHT_FL_PIXENC_RGB},
0028 { V4L2_PIX_FMT_RGB24, 3, 3, 1, 3, 3, 1, 1, 3, 1, V4L2_FWHT_FL_PIXENC_RGB},
0029 { V4L2_PIX_FMT_HSV24, 3, 3, 1, 3, 3, 1, 1, 3, 1, V4L2_FWHT_FL_PIXENC_HSV},
0030 { V4L2_PIX_FMT_BGR32, 4, 4, 1, 4, 4, 1, 1, 4, 1, V4L2_FWHT_FL_PIXENC_RGB},
0031 { V4L2_PIX_FMT_XBGR32, 4, 4, 1, 4, 4, 1, 1, 4, 1, V4L2_FWHT_FL_PIXENC_RGB},
0032 { V4L2_PIX_FMT_ABGR32, 4, 4, 1, 4, 4, 1, 1, 4, 1, V4L2_FWHT_FL_PIXENC_RGB},
0033 { V4L2_PIX_FMT_RGB32, 4, 4, 1, 4, 4, 1, 1, 4, 1, V4L2_FWHT_FL_PIXENC_RGB},
0034 { V4L2_PIX_FMT_XRGB32, 4, 4, 1, 4, 4, 1, 1, 4, 1, V4L2_FWHT_FL_PIXENC_RGB},
0035 { V4L2_PIX_FMT_ARGB32, 4, 4, 1, 4, 4, 1, 1, 4, 1, V4L2_FWHT_FL_PIXENC_RGB},
0036 { V4L2_PIX_FMT_BGRX32, 4, 4, 1, 4, 4, 1, 1, 4, 1, V4L2_FWHT_FL_PIXENC_RGB},
0037 { V4L2_PIX_FMT_BGRA32, 4, 4, 1, 4, 4, 1, 1, 4, 1, V4L2_FWHT_FL_PIXENC_RGB},
0038 { V4L2_PIX_FMT_RGBX32, 4, 4, 1, 4, 4, 1, 1, 4, 1, V4L2_FWHT_FL_PIXENC_RGB},
0039 { V4L2_PIX_FMT_RGBA32, 4, 4, 1, 4, 4, 1, 1, 4, 1, V4L2_FWHT_FL_PIXENC_RGB},
0040 { V4L2_PIX_FMT_HSV32, 4, 4, 1, 4, 4, 1, 1, 4, 1, V4L2_FWHT_FL_PIXENC_HSV},
0041 { V4L2_PIX_FMT_GREY, 1, 1, 1, 1, 0, 1, 1, 1, 1, V4L2_FWHT_FL_PIXENC_RGB},
0042 };
0043
0044 bool v4l2_fwht_validate_fmt(const struct v4l2_fwht_pixfmt_info *info,
0045 u32 width_div, u32 height_div, u32 components_num,
0046 u32 pixenc)
0047 {
0048 if (info->width_div == width_div &&
0049 info->height_div == height_div &&
0050 (!pixenc || info->pixenc == pixenc) &&
0051 info->components_num == components_num)
0052 return true;
0053 return false;
0054 }
0055
0056 const struct v4l2_fwht_pixfmt_info *v4l2_fwht_find_nth_fmt(u32 width_div,
0057 u32 height_div,
0058 u32 components_num,
0059 u32 pixenc,
0060 unsigned int start_idx)
0061 {
0062 unsigned int i;
0063
0064 for (i = 0; i < ARRAY_SIZE(v4l2_fwht_pixfmts); i++) {
0065 bool is_valid = v4l2_fwht_validate_fmt(&v4l2_fwht_pixfmts[i],
0066 width_div, height_div,
0067 components_num, pixenc);
0068 if (is_valid) {
0069 if (start_idx == 0)
0070 return v4l2_fwht_pixfmts + i;
0071 start_idx--;
0072 }
0073 }
0074 return NULL;
0075 }
0076
0077 const struct v4l2_fwht_pixfmt_info *v4l2_fwht_find_pixfmt(u32 pixelformat)
0078 {
0079 unsigned int i;
0080
0081 for (i = 0; i < ARRAY_SIZE(v4l2_fwht_pixfmts); i++)
0082 if (v4l2_fwht_pixfmts[i].id == pixelformat)
0083 return v4l2_fwht_pixfmts + i;
0084 return NULL;
0085 }
0086
0087 const struct v4l2_fwht_pixfmt_info *v4l2_fwht_get_pixfmt(u32 idx)
0088 {
0089 if (idx >= ARRAY_SIZE(v4l2_fwht_pixfmts))
0090 return NULL;
0091 return v4l2_fwht_pixfmts + idx;
0092 }
0093
0094 static int prepare_raw_frame(struct fwht_raw_frame *rf,
0095 const struct v4l2_fwht_pixfmt_info *info, u8 *buf,
0096 unsigned int size)
0097 {
0098 rf->luma = buf;
0099 rf->width_div = info->width_div;
0100 rf->height_div = info->height_div;
0101 rf->luma_alpha_step = info->luma_alpha_step;
0102 rf->chroma_step = info->chroma_step;
0103 rf->alpha = NULL;
0104 rf->components_num = info->components_num;
0105
0106
0107
0108
0109
0110 if (!buf) {
0111 rf->luma = NULL;
0112 rf->cb = NULL;
0113 rf->cr = NULL;
0114 rf->alpha = NULL;
0115 return 0;
0116 }
0117 switch (info->id) {
0118 case V4L2_PIX_FMT_GREY:
0119 rf->cb = NULL;
0120 rf->cr = NULL;
0121 break;
0122 case V4L2_PIX_FMT_YUV420:
0123 rf->cb = rf->luma + size;
0124 rf->cr = rf->cb + size / 4;
0125 break;
0126 case V4L2_PIX_FMT_YVU420:
0127 rf->cr = rf->luma + size;
0128 rf->cb = rf->cr + size / 4;
0129 break;
0130 case V4L2_PIX_FMT_YUV422P:
0131 rf->cb = rf->luma + size;
0132 rf->cr = rf->cb + size / 2;
0133 break;
0134 case V4L2_PIX_FMT_NV12:
0135 case V4L2_PIX_FMT_NV16:
0136 case V4L2_PIX_FMT_NV24:
0137 rf->cb = rf->luma + size;
0138 rf->cr = rf->cb + 1;
0139 break;
0140 case V4L2_PIX_FMT_NV21:
0141 case V4L2_PIX_FMT_NV61:
0142 case V4L2_PIX_FMT_NV42:
0143 rf->cr = rf->luma + size;
0144 rf->cb = rf->cr + 1;
0145 break;
0146 case V4L2_PIX_FMT_YUYV:
0147 rf->cb = rf->luma + 1;
0148 rf->cr = rf->cb + 2;
0149 break;
0150 case V4L2_PIX_FMT_YVYU:
0151 rf->cr = rf->luma + 1;
0152 rf->cb = rf->cr + 2;
0153 break;
0154 case V4L2_PIX_FMT_UYVY:
0155 rf->cb = rf->luma;
0156 rf->cr = rf->cb + 2;
0157 rf->luma++;
0158 break;
0159 case V4L2_PIX_FMT_VYUY:
0160 rf->cr = rf->luma;
0161 rf->cb = rf->cr + 2;
0162 rf->luma++;
0163 break;
0164 case V4L2_PIX_FMT_RGB24:
0165 case V4L2_PIX_FMT_HSV24:
0166 rf->cr = rf->luma;
0167 rf->cb = rf->cr + 2;
0168 rf->luma++;
0169 break;
0170 case V4L2_PIX_FMT_BGR24:
0171 rf->cb = rf->luma;
0172 rf->cr = rf->cb + 2;
0173 rf->luma++;
0174 break;
0175 case V4L2_PIX_FMT_RGB32:
0176 case V4L2_PIX_FMT_XRGB32:
0177 case V4L2_PIX_FMT_HSV32:
0178 case V4L2_PIX_FMT_ARGB32:
0179 rf->alpha = rf->luma;
0180 rf->cr = rf->luma + 1;
0181 rf->cb = rf->cr + 2;
0182 rf->luma += 2;
0183 break;
0184 case V4L2_PIX_FMT_BGR32:
0185 case V4L2_PIX_FMT_XBGR32:
0186 case V4L2_PIX_FMT_ABGR32:
0187 rf->cb = rf->luma;
0188 rf->cr = rf->cb + 2;
0189 rf->luma++;
0190 rf->alpha = rf->cr + 1;
0191 break;
0192 case V4L2_PIX_FMT_BGRX32:
0193 case V4L2_PIX_FMT_BGRA32:
0194 rf->alpha = rf->luma;
0195 rf->cb = rf->luma + 1;
0196 rf->cr = rf->cb + 2;
0197 rf->luma += 2;
0198 break;
0199 case V4L2_PIX_FMT_RGBX32:
0200 case V4L2_PIX_FMT_RGBA32:
0201 rf->alpha = rf->luma + 3;
0202 rf->cr = rf->luma;
0203 rf->cb = rf->cr + 2;
0204 rf->luma++;
0205 break;
0206 default:
0207 return -EINVAL;
0208 }
0209 return 0;
0210 }
0211
0212 int v4l2_fwht_encode(struct v4l2_fwht_state *state, u8 *p_in, u8 *p_out)
0213 {
0214 unsigned int size = state->stride * state->coded_height;
0215 unsigned int chroma_stride = state->stride;
0216 const struct v4l2_fwht_pixfmt_info *info = state->info;
0217 struct fwht_cframe_hdr *p_hdr;
0218 struct fwht_cframe cf;
0219 struct fwht_raw_frame rf;
0220 u32 encoding;
0221 u32 flags = 0;
0222
0223 if (!info)
0224 return -EINVAL;
0225
0226 if (prepare_raw_frame(&rf, info, p_in, size))
0227 return -EINVAL;
0228
0229 if (info->planes_num == 3)
0230 chroma_stride /= 2;
0231
0232 if (info->id == V4L2_PIX_FMT_NV24 ||
0233 info->id == V4L2_PIX_FMT_NV42)
0234 chroma_stride *= 2;
0235
0236 cf.i_frame_qp = state->i_frame_qp;
0237 cf.p_frame_qp = state->p_frame_qp;
0238 cf.rlc_data = (__be16 *)(p_out + sizeof(*p_hdr));
0239
0240 encoding = fwht_encode_frame(&rf, &state->ref_frame, &cf,
0241 !state->gop_cnt,
0242 state->gop_cnt == state->gop_size - 1,
0243 state->visible_width,
0244 state->visible_height,
0245 state->stride, chroma_stride);
0246 if (!(encoding & FWHT_FRAME_PCODED))
0247 state->gop_cnt = 0;
0248 if (++state->gop_cnt >= state->gop_size)
0249 state->gop_cnt = 0;
0250
0251 p_hdr = (struct fwht_cframe_hdr *)p_out;
0252 p_hdr->magic1 = FWHT_MAGIC1;
0253 p_hdr->magic2 = FWHT_MAGIC2;
0254 p_hdr->version = htonl(V4L2_FWHT_VERSION);
0255 p_hdr->width = htonl(state->visible_width);
0256 p_hdr->height = htonl(state->visible_height);
0257 flags |= (info->components_num - 1) << V4L2_FWHT_FL_COMPONENTS_NUM_OFFSET;
0258 flags |= info->pixenc;
0259 if (encoding & FWHT_LUMA_UNENCODED)
0260 flags |= V4L2_FWHT_FL_LUMA_IS_UNCOMPRESSED;
0261 if (encoding & FWHT_CB_UNENCODED)
0262 flags |= V4L2_FWHT_FL_CB_IS_UNCOMPRESSED;
0263 if (encoding & FWHT_CR_UNENCODED)
0264 flags |= V4L2_FWHT_FL_CR_IS_UNCOMPRESSED;
0265 if (encoding & FWHT_ALPHA_UNENCODED)
0266 flags |= V4L2_FWHT_FL_ALPHA_IS_UNCOMPRESSED;
0267 if (!(encoding & FWHT_FRAME_PCODED))
0268 flags |= V4L2_FWHT_FL_I_FRAME;
0269 if (rf.height_div == 1)
0270 flags |= V4L2_FWHT_FL_CHROMA_FULL_HEIGHT;
0271 if (rf.width_div == 1)
0272 flags |= V4L2_FWHT_FL_CHROMA_FULL_WIDTH;
0273 p_hdr->flags = htonl(flags);
0274 p_hdr->colorspace = htonl(state->colorspace);
0275 p_hdr->xfer_func = htonl(state->xfer_func);
0276 p_hdr->ycbcr_enc = htonl(state->ycbcr_enc);
0277 p_hdr->quantization = htonl(state->quantization);
0278 p_hdr->size = htonl(cf.size);
0279 return cf.size + sizeof(*p_hdr);
0280 }
0281
0282 int v4l2_fwht_decode(struct v4l2_fwht_state *state, u8 *p_in, u8 *p_out)
0283 {
0284 u32 flags;
0285 struct fwht_cframe cf;
0286 unsigned int components_num = 3;
0287 unsigned int version;
0288 const struct v4l2_fwht_pixfmt_info *info;
0289 unsigned int hdr_width_div, hdr_height_div;
0290 struct fwht_raw_frame dst_rf;
0291 unsigned int dst_chroma_stride = state->stride;
0292 unsigned int ref_chroma_stride = state->ref_stride;
0293 unsigned int dst_size = state->stride * state->coded_height;
0294 unsigned int ref_size;
0295
0296 if (!state->info)
0297 return -EINVAL;
0298
0299 info = state->info;
0300
0301 version = ntohl(state->header.version);
0302 if (!version || version > V4L2_FWHT_VERSION) {
0303 pr_err("version %d is not supported, current version is %d\n",
0304 version, V4L2_FWHT_VERSION);
0305 return -EINVAL;
0306 }
0307
0308 if (state->header.magic1 != FWHT_MAGIC1 ||
0309 state->header.magic2 != FWHT_MAGIC2)
0310 return -EINVAL;
0311
0312
0313 if (ntohl(state->header.width) != state->visible_width ||
0314 ntohl(state->header.height) != state->visible_height)
0315 return -EINVAL;
0316
0317 flags = ntohl(state->header.flags);
0318
0319 if (version >= 2) {
0320 if ((flags & V4L2_FWHT_FL_PIXENC_MSK) != info->pixenc)
0321 return -EINVAL;
0322 components_num = 1 + ((flags & V4L2_FWHT_FL_COMPONENTS_NUM_MSK) >>
0323 V4L2_FWHT_FL_COMPONENTS_NUM_OFFSET);
0324 }
0325
0326 if (components_num != info->components_num)
0327 return -EINVAL;
0328
0329 state->colorspace = ntohl(state->header.colorspace);
0330 state->xfer_func = ntohl(state->header.xfer_func);
0331 state->ycbcr_enc = ntohl(state->header.ycbcr_enc);
0332 state->quantization = ntohl(state->header.quantization);
0333 cf.rlc_data = (__be16 *)p_in;
0334 cf.size = ntohl(state->header.size);
0335
0336 hdr_width_div = (flags & V4L2_FWHT_FL_CHROMA_FULL_WIDTH) ? 1 : 2;
0337 hdr_height_div = (flags & V4L2_FWHT_FL_CHROMA_FULL_HEIGHT) ? 1 : 2;
0338 if (hdr_width_div != info->width_div ||
0339 hdr_height_div != info->height_div)
0340 return -EINVAL;
0341
0342 if (prepare_raw_frame(&dst_rf, info, p_out, dst_size))
0343 return -EINVAL;
0344 if (info->planes_num == 3) {
0345 dst_chroma_stride /= 2;
0346 ref_chroma_stride /= 2;
0347 }
0348 if (info->id == V4L2_PIX_FMT_NV24 ||
0349 info->id == V4L2_PIX_FMT_NV42) {
0350 dst_chroma_stride *= 2;
0351 ref_chroma_stride *= 2;
0352 }
0353
0354
0355 ref_size = state->ref_stride * state->coded_height;
0356
0357 if (prepare_raw_frame(&state->ref_frame, info, state->ref_frame.buf,
0358 ref_size))
0359 return -EINVAL;
0360
0361 if (!fwht_decode_frame(&cf, flags, components_num,
0362 state->visible_width, state->visible_height,
0363 &state->ref_frame, state->ref_stride, ref_chroma_stride,
0364 &dst_rf, state->stride, dst_chroma_stride))
0365 return -EINVAL;
0366 return 0;
0367 }