codec-v4l2-fwht.c 11 KB

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