Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: LGPL-2.1
0002 /*
0003  * A V4L2 frontend for the FWHT codec
0004  *
0005  * Copyright 2018 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
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      * The buffer is NULL if it is the reference
0108      * frame of an I-frame in the stateless decoder
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     /* TODO: support resolution changes */
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 }