21#include <freerdp/codec/av1.h>
22#include <freerdp/primitives.h>
23#include <freerdp/log.h>
25#define TAG FREERDP_TAG("codec.av1")
27#if defined(WITH_LIBAOM)
30#include <aom/aom_decoder.h>
31#include <aom/aom_encoder.h>
33#include <aom/aom_image.h>
37#if defined(WITH_LIBYUV)
41struct S_FREERDP_AV1_CONTEXT
47 aom_codec_enc_cfg_t ecfg;
48 aom_codec_dec_cfg_t dcfg;
49 aom_codec_pts_t framecount;
50 aom_enc_frame_flags_t eflags;
51 aom_codec_flags_t flags;
52 aom_codec_iface_t* iface;
60static BOOL allocate_h264_metablock(UINT32 QP,
RECTANGLE_16* rectangles,
64 if (!meta || (QP > UINT8_MAX))
70 meta->regionRects = rectangles;
74 if (count > UINT32_MAX)
79 if (!meta->quantQualityVals || !meta->regionRects)
81 meta->numRegionRects = (UINT32)count;
82 for (
size_t x = 0; x < count; x++)
89 cur->qualityVal = 100 - (QP & 0x3F);
94BOOL freerdp_av1_context_set_option(FREERDP_AV1_CONTEXT* av1, FREERDP_AV1_CONTEXT_OPTION option,
100 case FREERDP_AV1_CONTEXT_OPTION_PROFILE:
104 av1->ecfg.g_profile = value;
107 case FREERDP_AV1_CONTEXT_OPTION_RATECONTROL:
112 case FREERDP_AV1_VBR:
113 case FREERDP_AV1_CBR:
118 WLog_Print(av1->log, WLOG_WARN,
119 "Unknown FREERDP_AV1_CONTEXT_OPTION_RATECONTROL value [0x%08" PRIx32
124 av1->ecfg.rc_end_usage = value;
126 case FREERDP_AV1_CONTEXT_OPTION_BITRATE:
129 av1->ecfg.rc_target_bitrate = value;
131 case FREERDP_AV1_CONTEXT_OPTION_USAGETYPE:
134 av1->ecfg.g_usage = value;
137 WLog_Print(av1->log, WLOG_ERROR,
"Unknown FREERDP_AV1_CONTEXT_OPTION[0x%08" PRIx32
"]",
141 return freerdp_av1_context_reset(av1, av1->ecfg.g_w, av1->ecfg.g_h);
144UINT32 freerdp_av1_context_get_option(FREERDP_AV1_CONTEXT* av1, FREERDP_AV1_CONTEXT_OPTION option)
148 case FREERDP_AV1_CONTEXT_OPTION_PROFILE:
151 return av1->ecfg.g_profile;
152 case FREERDP_AV1_CONTEXT_OPTION_RATECONTROL:
155 return av1->ecfg.rc_end_usage;
156 case FREERDP_AV1_CONTEXT_OPTION_BITRATE:
159 return av1->ecfg.rc_target_bitrate;
160 case FREERDP_AV1_CONTEXT_OPTION_USAGETYPE:
163 return av1->ecfg.g_usage;
165 WLog_Print(av1->log, WLOG_ERROR,
"Unknown FREERDP_AV1_CONTEXT_OPTION[0x%08" PRIx32
"]",
171INT32 freerdp_av1_compress(FREERDP_AV1_CONTEXT* av1,
const BYTE* pSrcData, DWORD SrcFormat,
172 UINT32 nSrcStep, UINT32 nSrcWidth, UINT32 nSrcHeight,
173 const RECTANGLE_16* regionRect, BYTE** ppDstData, UINT32* pDstSize,
176 *ppDstData =
nullptr;
181 WLog_Print(av1->log, WLOG_ERROR,
"av1->encoder: %d", av1->encoder);
188 WLog_Print(av1->log, WLOG_ERROR,
"primitives_get(): nullptr");
192 if (av1->yuvWidth != nSrcWidth)
194 WLog_Print(av1->log, WLOG_ERROR,
"av1->yuvWidth[%" PRIu32
"] != nSrcWidth[%" PRIu32
"]",
195 av1->yuvWidth, nSrcWidth);
199 if (av1->yuvHeight != nSrcHeight)
201 WLog_Print(av1->log, WLOG_ERROR,
"av1->yuvHeight[%" PRIu32
"] != nSrcHeight[%" PRIu32
"]",
202 av1->yuvHeight, nSrcHeight);
206 const prim_size_t roi = { .width = nSrcWidth, .height = nSrcHeight };
208 aom_image_t buffer = { 0 };
210 aom_image_t* img = &buffer;
211#if defined(WITH_LIBYUV)
213 switch (av1->ecfg.g_profile)
216 img->fmt = AOM_IMG_FMT_I420;
217 img->x_chroma_shift = 1;
218 img->y_chroma_shift = 1;
219 rec = ARGBToI420(pSrcData, nSrcStep, av1->yuvdata[0], av1->yuvStride[0],
220 av1->yuvdata[1], av1->yuvStride[1], av1->yuvdata[2],
221 WINPR_ASSERTING_INT_CAST(
int, av1->yuvStride[2]),
222 WINPR_ASSERTING_INT_CAST(
int, roi.width),
223 WINPR_ASSERTING_INT_CAST(
int, roi.height));
226 img->fmt = AOM_IMG_FMT_I444;
227 rec = ARGBToI444(pSrcData, nSrcStep, av1->yuvdata[0], av1->yuvStride[0],
228 av1->yuvdata[1], av1->yuvStride[1], av1->yuvdata[2],
229 WINPR_ASSERTING_INT_CAST(
int, av1->yuvStride[2]),
230 WINPR_ASSERTING_INT_CAST(
int, roi.width),
231 WINPR_ASSERTING_INT_CAST(
int, roi.height));
234 WLog_Print(av1->log, WLOG_ERROR,
"Unsupoorted AV1 profile %" PRIu32,
235 av1->ecfg.g_profile);
240 WLog_Print(av1->log, WLOG_ERROR,
"ARGBToI444(): %d", rec);
245 switch (av1->ecfg.g_profile)
248 img->fmt = AOM_IMG_FMT_I420;
249 img->x_chroma_shift = 1;
250 img->y_chroma_shift = 1;
251 rec = primitives->RGBToYUV420_8u_P3AC4R(pSrcData, SrcFormat, nSrcStep, av1->yuvdata,
252 av1->yuvStride, &roi);
255 img->fmt = AOM_IMG_FMT_I444;
256 rec = primitives->
RGBToI444_8u(pSrcData, SrcFormat, nSrcStep, av1->yuvdata,
257 av1->yuvStride, &roi);
260 WLog_Print(av1->log, WLOG_ERROR,
"Unsupoorted AV1 profile %" PRIu32,
261 av1->ecfg.g_profile);
266 WLog_Print(av1->log, WLOG_ERROR,
"primitives->RGBToI444_8u(): %d", rec);
271 img->d_w = img->r_w = img->w = roi.width;
272 img->d_h = img->r_h = img->h = roi.height;
273 img->stride[0] = WINPR_ASSERTING_INT_CAST(
int, av1->yuvStride[0]);
274 img->stride[1] = WINPR_ASSERTING_INT_CAST(
int, av1->yuvStride[1]);
275 img->stride[2] = WINPR_ASSERTING_INT_CAST(
int, av1->yuvStride[2]);
276 img->planes[0] = av1->yuvdata[0];
277 img->planes[1] = av1->yuvdata[1];
278 img->planes[2] = av1->yuvdata[2];
280 const aom_codec_err_t rc = aom_codec_encode(&av1->ctx, img, ++av1->framecount, 1, av1->eflags);
283 if (rc != AOM_CODEC_OK)
285 WLog_Print(av1->log, WLOG_WARN,
"aom_codec_encode: %s", aom_codec_err_to_string(rc));
289 aom_codec_iter_t iter =
nullptr;
290 const aom_codec_cx_pkt_t* pkt =
nullptr;
291 while ((pkt = aom_codec_get_cx_data(&av1->ctx, &iter)) !=
nullptr)
293 if (pkt->kind != AOM_CODEC_CX_FRAME_PKT)
296 *ppDstData = pkt->data.frame.buf;
297 *pDstSize = pkt->data.frame.sz;
305 rect->right = nSrcWidth;
306 rect->bottom = nSrcHeight;
308 return allocate_h264_metablock(10, rect, meta, 1);
311INT32 freerdp_av1_decompress(FREERDP_AV1_CONTEXT* av1,
const BYTE* pSrcData, UINT32 SrcSize,
312 BYTE* pDstData, DWORD DstFormat, UINT32 nDstStep, UINT32 nDstWidth,
314 UINT32 numRegionRect)
319 WLog_Print(av1->log, WLOG_ERROR,
"av1->encoder: %d", av1->encoder);
323 const aom_codec_err_t rc = aom_codec_decode(&av1->ctx, pSrcData, SrcSize,
nullptr);
324 if (rc != AOM_CODEC_OK)
326 WLog_Print(av1->log, WLOG_WARN,
"aom_codec_decode: %s", aom_codec_err_to_string(rc));
330 aom_image_t* img =
nullptr;
331 aom_codec_iter_t iter =
nullptr;
332 while ((img = aom_codec_get_frame(&av1->ctx, &iter)) !=
nullptr)
334 const prim_size_t roi = { .width = nDstWidth, .height = nDstHeight };
336#if defined(WITH_LIBYUV)
341 case AOM_IMG_FMT_I420:
342 rec = J420ToARGB(img->planes[0], img->stride[0], img->planes[1], img->stride[1],
343 img->planes[2], img->stride[2], pDstData, nDstStep, nDstWidth,
346 case AOM_IMG_FMT_I444:
347 rec = J444ToARGB(img->planes[0], img->stride[0], img->planes[1], img->stride[1],
348 img->planes[2], img->stride[2], pDstData, nDstStep, nDstWidth,
352 WLog_Print(av1->log, WLOG_ERROR,
"img->fmt %d not supported", img->fmt);
357 WLog_Print(av1->log, WLOG_ERROR,
"I444ToABGR() %d", rec);
361 const BYTE* pSrc[] = { img->planes[0], img->planes[1], img->planes[2] };
362 const UINT32 strides[] = { img->stride[0], img->stride[1], img->stride[2] };
367 WLog_Print(av1->log, WLOG_ERROR,
"primitives_get(): nullptr");
374 case AOM_IMG_FMT_I420:
375 rec = primitives->YUV420ToRGB_8u_P3AC4R(pSrc, strides, pDstData, nDstStep,
378 case AOM_IMG_FMT_I444:
379 rec = primitives->YUV444ToRGB_8u_P3AC4R(pSrc, strides, pDstData, nDstStep,
383 WLog_Print(av1->log, WLOG_ERROR,
"img->fmt %d not supported", img->fmt);
388 WLog_Print(av1->log, WLOG_ERROR,
"I444ToABGR() %d", rec);
397BOOL freerdp_av1_context_reset(FREERDP_AV1_CONTEXT* av1, UINT32 width, UINT32 height)
401 av1->ecfg.g_w = width;
402 av1->ecfg.g_h = height;
404 if (av1->initialized)
406 const aom_codec_err_t rc = aom_codec_destroy(&av1->ctx);
407 av1->initialized =
false;
408 if (rc != AOM_CODEC_OK)
410 WLog_Print(av1->log, WLOG_WARN,
"aom_codec_destroy: %s",
411 aom_codec_err_to_string(rc));
416 const aom_codec_err_t rc =
417 aom_codec_enc_init(&av1->ctx, av1->iface, &av1->ecfg, av1->flags);
418 if (rc != AOM_CODEC_OK)
420 WLog_Print(av1->log, WLOG_WARN,
"aom_codec_enc_init: %s", aom_codec_err_to_string(rc));
430 av1->dcfg.h = height;
431 av1->dcfg.allow_lowbitdepth = 1;
432 const aom_codec_err_t rc =
433 aom_codec_dec_init(&av1->ctx, av1->iface, &av1->dcfg, av1->flags);
434 if (rc != AOM_CODEC_OK)
436 WLog_Print(av1->log, WLOG_WARN,
"aom_codec_dec_init: %s", aom_codec_err_to_string(rc));
440 av1->initialized =
true;
442 av1->yuvWidth = width;
443 av1->yuvStride[0] = width;
445 const size_t pad = av1->yuvStride[0] % 16;
447 av1->yuvStride[0] += 16 - pad;
448 av1->yuvStride[0] *= 3;
449 av1->yuvStride[1] = width;
450 av1->yuvStride[2] = width;
452 av1->yuvHeight = height;
453 winpr_aligned_free(av1->yuvdata[0]);
454 winpr_aligned_free(av1->yuvdata[1]);
455 winpr_aligned_free(av1->yuvdata[2]);
456 av1->yuvdata[0] = winpr_aligned_malloc(1ull * av1->yuvStride[0] * av1->yuvHeight, 64);
457 av1->yuvdata[1] = winpr_aligned_malloc(1ull * av1->yuvStride[1] * av1->yuvHeight, 64);
458 av1->yuvdata[2] = winpr_aligned_malloc(1ull * av1->yuvStride[2] * av1->yuvHeight, 64);
459 return av1->yuvdata[0] !=
nullptr;
462void freerdp_av1_context_free(FREERDP_AV1_CONTEXT* av1)
467 if (av1->initialized)
469 const aom_codec_err_t rc = aom_codec_destroy(&av1->ctx);
470 if (rc != AOM_CODEC_OK)
472 WLog_Print(av1->log, WLOG_WARN,
"aom_codec_destroy: %s", aom_codec_err_to_string(rc));
475 winpr_aligned_free(av1->yuvdata[0]);
476 winpr_aligned_free(av1->yuvdata[1]);
477 winpr_aligned_free(av1->yuvdata[2]);
481FREERDP_AV1_CONTEXT* freerdp_av1_context_new(BOOL Compressor)
483 FREERDP_AV1_CONTEXT* ctx = calloc(1,
sizeof(FREERDP_AV1_CONTEXT));
486 ctx->encoder = Compressor;
487 ctx->log = WLog_Get(TAG);
493 ctx->iface = aom_codec_av1_cx();
496 WLog_Print(ctx->log, WLOG_ERROR,
"aom_codec_av1_cx() nullptr");
500 const aom_codec_err_t rc =
501 aom_codec_enc_config_default(ctx->iface, &ctx->ecfg, AOM_USAGE_REALTIME);
502 if (rc != AOM_CODEC_OK)
504 WLog_Print(ctx->log, WLOG_ERROR,
"aom_codec_enc_config_default() %s",
505 aom_codec_err_to_string(rc));
511 ctx->iface = aom_codec_av1_dx();
514 WLog_Print(ctx->log, WLOG_ERROR,
"aom_codec_av1_dx() nullptr");
522 freerdp_av1_context_free(ctx);
527struct S_FREERDP_AV1_CONTEXT
533BOOL freerdp_av1_context_set_option(WINPR_ATTR_UNUSED FREERDP_AV1_CONTEXT* av1,
534 WINPR_ATTR_UNUSED FREERDP_AV1_CONTEXT_OPTION option,
535 WINPR_ATTR_UNUSED UINT32 value)
540UINT32 freerdp_av1_context_get_option(WINPR_ATTR_UNUSED FREERDP_AV1_CONTEXT* av1,
541 WINPR_ATTR_UNUSED FREERDP_AV1_CONTEXT_OPTION option)
546INT32 freerdp_av1_compress(WINPR_ATTR_UNUSED FREERDP_AV1_CONTEXT* av1,
547 WINPR_ATTR_UNUSED
const BYTE* pSrcData,
548 WINPR_ATTR_UNUSED DWORD SrcFormat, WINPR_ATTR_UNUSED UINT32 nSrcStep,
549 WINPR_ATTR_UNUSED UINT32 nSrcWidth, WINPR_ATTR_UNUSED UINT32 nSrcHeight,
551 WINPR_ATTR_UNUSED BYTE** ppDstData, WINPR_ATTR_UNUSED UINT32* pDstSize,
555 WLog_Print(av1->log, WLOG_ERROR,
556 "This build does not support AV1 codec. Recompile with '-DWITH_AOM=ON'");
560INT32 freerdp_av1_decompress(WINPR_ATTR_UNUSED FREERDP_AV1_CONTEXT* av1,
561 WINPR_ATTR_UNUSED
const BYTE* pSrcData,
562 WINPR_ATTR_UNUSED UINT32 SrcSize, WINPR_ATTR_UNUSED BYTE* pDstData,
563 WINPR_ATTR_UNUSED DWORD DstFormat, WINPR_ATTR_UNUSED UINT32 nDstStep,
564 WINPR_ATTR_UNUSED UINT32 nDstWidth,
565 WINPR_ATTR_UNUSED UINT32 nDstHeight,
567 WINPR_ATTR_UNUSED UINT32 numRegionRect)
570 WLog_Print(av1->log, WLOG_ERROR,
571 "This build does not support AV1 codec. Recompile with '-DWITH_AOM=ON'");
575BOOL freerdp_av1_context_reset(WINPR_ATTR_UNUSED FREERDP_AV1_CONTEXT* av1,
576 WINPR_ATTR_UNUSED UINT32 width, WINPR_ATTR_UNUSED UINT32 height)
579 WLog_Print(av1->log, WLOG_WARN,
580 "This build does not support AV1 codec. Recompile with '-DWITH_AOM=ON'");
584void freerdp_av1_context_free(WINPR_ATTR_UNUSED FREERDP_AV1_CONTEXT* av1)
589FREERDP_AV1_CONTEXT* freerdp_av1_context_new(BOOL Compressor)
591 FREERDP_AV1_CONTEXT* ctx = calloc(1,
sizeof(FREERDP_AV1_CONTEXT));
594 ctx->Compressor = Compressor;
595 ctx->log = WLog_Get(TAG);
WINPR_ATTR_NODISCARD fn_RGBToYUV444_8u_P3AC4R_t RGBToI444_8u