21#include <winpr/sysinfo.h>
23#include <freerdp/codec/av1.h>
24#include <freerdp/primitives.h>
25#include <freerdp/log.h>
26#include <freerdp/codec/region.h>
28#define TAG FREERDP_TAG("codec.av1")
30#if defined(WITH_LIBAOM)
33#include <aom/aom_decoder.h>
34#include <aom/aom_encoder.h>
36#include <aom/aom_image.h>
41#if defined(WITH_DAV1D)
42#include <dav1d/dav1d.h>
45#if defined(WITH_AV1_WEBCODECS)
46#include "av1_webcodecs.h"
49#if defined(WITH_LIBAOM) || defined(WITH_DAV1D)
51#if defined(WITH_LIBYUV)
55struct S_FREERDP_AV1_CONTEXT
60#if defined(WITH_LIBAOM)
62 aom_codec_enc_cfg_t ecfg;
63 aom_codec_pts_t framecount;
64 aom_enc_frame_flags_t eflags;
65 aom_codec_flags_t flags;
66 aom_codec_iface_t* iface;
79#if defined(WITH_LIBAOM) && !defined(WITH_DAV1D)
80 aom_codec_dec_cfg_t dcfg;
82#if defined(WITH_DAV1D)
85#if defined(WITH_AV1_WEBCODECS)
94#if defined(WITH_LIBAOM)
95static void av1_aom_destroy(FREERDP_AV1_CONTEXT* av1)
97 const aom_codec_err_t rc = aom_codec_destroy(&av1->ctx);
98 if (rc != AOM_CODEC_OK)
99 WLog_Print(av1->log, WLOG_WARN,
"aom_codec_destroy: %s", aom_codec_err_to_string(rc));
105#define AV1_AOM_RT_SPEED 10
108#define AV1_AOM_MAX_THREADS 4
110static unsigned int av1_aom_threads(
void)
113 GetNativeSystemInfo(&sysInfo);
114 if (sysInfo.dwNumberOfProcessors < 1)
116 if (sysInfo.dwNumberOfProcessors > AV1_AOM_MAX_THREADS)
117 return AV1_AOM_MAX_THREADS;
118 return sysInfo.dwNumberOfProcessors;
123static BOOL av1_aom_apply_controls(FREERDP_AV1_CONTEXT* av1)
131 { AOME_SET_CPUUSED, AV1_AOM_RT_SPEED,
"AOME_SET_CPUUSED" },
133 { AV1E_SET_TUNE_CONTENT, AOM_CONTENT_SCREEN,
"AV1E_SET_TUNE_CONTENT" },
134 { AV1E_SET_ROW_MT, 1,
"AV1E_SET_ROW_MT" },
137 for (
size_t x = 0; x < ARRAYSIZE(controls); x++)
139 const aom_codec_err_t rc = aom_codec_control(&av1->ctx, controls[x].id, controls[x].value);
140 if (rc != AOM_CODEC_OK)
142 WLog_Print(av1->log, WLOG_WARN,
"aom_codec_control(%s, %d): %s", controls[x].name,
143 controls[x].value, aom_codec_err_to_string(rc));
153static BOOL av1_aom_damage(
const FREERDP_AV1_CONTEXT* av1,
const RECTANGLE_16* regionRect,
156 if (av1->fullFrameNext || !regionRect)
159 const UINT32 left = regionRect->left & ~1u;
160 const UINT32 top = regionRect->top & ~1u;
161 const UINT32 right = MIN(width, (regionRect->right + 1u) & ~1u);
162 const UINT32 bottom = MIN(height, (regionRect->bottom + 1u) & ~1u);
163 if ((left >= right) || (top >= bottom))
165 if ((left == 0) && (top == 0) && (right == width) && (bottom == height))
168 damage->left = (UINT16)left;
169 damage->top = (UINT16)top;
170 damage->right = (UINT16)right;
171 damage->bottom = (UINT16)bottom;
176static BOOL allocate_h264_metablock(UINT32 QP,
RECTANGLE_16* rectangles,
180 if (!meta || (QP > UINT8_MAX))
186 meta->regionRects = rectangles;
190 if (count > UINT32_MAX)
195 if (!meta->quantQualityVals || !meta->regionRects)
197 meta->numRegionRects = (UINT32)count;
198 for (
size_t x = 0; x < count; x++)
205 cur->qualityVal = 100 - (QP & 0x3F);
212BOOL freerdp_av1_context_set_option(FREERDP_AV1_CONTEXT* av1, FREERDP_AV1_CONTEXT_OPTION option,
215#if defined(WITH_LIBAOM)
218 case FREERDP_AV1_CONTEXT_OPTION_PROFILE:
222 av1->ecfg.g_profile = value;
225 case FREERDP_AV1_CONTEXT_OPTION_RATECONTROL:
230 case FREERDP_AV1_VBR:
231 case FREERDP_AV1_CBR:
236 WLog_Print(av1->log, WLOG_WARN,
237 "Unknown FREERDP_AV1_CONTEXT_OPTION_RATECONTROL value [0x%08" PRIx32
242 av1->ecfg.rc_end_usage = value;
244 case FREERDP_AV1_CONTEXT_OPTION_BITRATE:
247 av1->ecfg.rc_target_bitrate = value;
249 case FREERDP_AV1_CONTEXT_OPTION_USAGETYPE:
252 av1->ecfg.g_usage = value;
255 WLog_Print(av1->log, WLOG_ERROR,
"Unknown FREERDP_AV1_CONTEXT_OPTION[0x%08" PRIx32
"]",
259 return freerdp_av1_context_reset(av1, av1->ecfg.g_w, av1->ecfg.g_h);
261 WLog_Print(av1->log, WLOG_WARN,
"AV1 encoder requires libaom, recompile with '-DWITH_AOM=ON'");
262 WINPR_UNUSED(option);
268UINT32 freerdp_av1_context_get_option(FREERDP_AV1_CONTEXT* av1, FREERDP_AV1_CONTEXT_OPTION option)
270#if defined(WITH_LIBAOM)
273 case FREERDP_AV1_CONTEXT_OPTION_PROFILE:
276 return av1->ecfg.g_profile;
277 case FREERDP_AV1_CONTEXT_OPTION_RATECONTROL:
280 return av1->ecfg.rc_end_usage;
281 case FREERDP_AV1_CONTEXT_OPTION_BITRATE:
284 return av1->ecfg.rc_target_bitrate;
285 case FREERDP_AV1_CONTEXT_OPTION_USAGETYPE:
288 return av1->ecfg.g_usage;
290 WLog_Print(av1->log, WLOG_ERROR,
"Unknown FREERDP_AV1_CONTEXT_OPTION[0x%08" PRIx32
"]",
295 WINPR_UNUSED(option);
300#if defined(WITH_LIBAOM)
303#define AV1_STATS_INTERVAL_NS (5ull * 1000ull * 1000ull * 1000ull)
305static void av1_encoder_stats(FREERDP_AV1_CONTEXT* av1, UINT64 startNS,
size_t bytes)
309 if (!WLog_IsLevelActive(av1->log, WLOG_DEBUG))
312 const UINT64 endNS = winpr_GetTickCount64NS();
313 const UINT64 encodeNS = endNS - startNS;
314 if (av1->stats.frames == 0)
315 av1->stats.startNS = startNS;
317 av1->stats.encodeNS += encodeNS;
318 av1->stats.bytes += bytes;
319 if (encodeNS > av1->stats.maxEncodeNS)
320 av1->stats.maxEncodeNS = encodeNS;
322 const UINT64 elapsedNS = endNS - av1->stats.startNS;
323 if (elapsedNS < AV1_STATS_INTERVAL_NS)
326 const double seconds = (double)elapsedNS / 1e9;
327 WLog_Print(av1->log, WLOG_DEBUG,
328 "AV1 %" PRIu32
"x%" PRIu32
" %s: %" PRIu32
" frames in %.1f s (%.1f fps), "
329 "encode avg %.1f ms max %.1f ms, %.0f kbit/s",
330 av1->yuvWidth, av1->yuvHeight, (av1->ecfg.g_profile == 1) ?
"I444" :
"I420",
331 av1->stats.frames, seconds, av1->stats.frames / seconds,
332 (double)av1->stats.encodeNS / av1->stats.frames / 1e6,
333 (double)av1->stats.maxEncodeNS / 1e6,
334 (double)av1->stats.bytes * 8.0 / 1000.0 / seconds);
336 av1->stats.frames = 0;
337 av1->stats.encodeNS = 0;
338 av1->stats.maxEncodeNS = 0;
339 av1->stats.bytes = 0;
343INT32 freerdp_av1_compress(FREERDP_AV1_CONTEXT* av1,
const BYTE* pSrcData, DWORD SrcFormat,
344 UINT32 nSrcStep, UINT32 nSrcWidth, UINT32 nSrcHeight,
345 const RECTANGLE_16* regionRect, BYTE** ppDstData, UINT32* pDstSize,
348 *ppDstData =
nullptr;
353 WLog_Print(av1->log, WLOG_ERROR,
"av1->encoder: %d", av1->encoder);
357#if defined(WITH_LIBAOM)
358 const UINT64 startNS = winpr_GetTickCount64NS();
362 WLog_Print(av1->log, WLOG_ERROR,
"primitives_get(): nullptr");
366 if (av1->yuvWidth != nSrcWidth)
368 WLog_Print(av1->log, WLOG_ERROR,
"av1->yuvWidth[%" PRIu32
"] != nSrcWidth[%" PRIu32
"]",
369 av1->yuvWidth, nSrcWidth);
373 if (av1->yuvHeight != nSrcHeight)
375 WLog_Print(av1->log, WLOG_ERROR,
"av1->yuvHeight[%" PRIu32
"] != nSrcHeight[%" PRIu32
"]",
376 av1->yuvHeight, nSrcHeight);
382 const BOOL partial = av1_aom_damage(av1, regionRect, nSrcWidth, nSrcHeight, &damage);
387 damage.right = WINPR_ASSERTING_INT_CAST(UINT16, nSrcWidth);
388 damage.bottom = WINPR_ASSERTING_INT_CAST(UINT16, nSrcHeight);
391 const UINT32 bpp = FreeRDPGetBytesPerPixel(SrcFormat);
394 WLog_Print(av1->log, WLOG_ERROR,
"Unsupported source format %s",
395 FreeRDPGetColorFormatName(SrcFormat));
399 const prim_size_t roi = { .width = damage.right - damage.left,
400 .height = damage.bottom - damage.top };
401 const UINT32 chromaShift = (av1->ecfg.g_profile == 0) ? 1 : 0;
402 const size_t chromaX = damage.left >> chromaShift;
403 const size_t chromaY = damage.top >> chromaShift;
404 const BYTE* pSrc = &pSrcData[1ull * damage.top * nSrcStep + 1ull * damage.left * bpp];
405 BYTE* pDst[3] = { &av1->yuvdata[0][1ull * damage.top * av1->yuvStride[0] + damage.left],
406 &av1->yuvdata[1][chromaY * av1->yuvStride[1] + chromaX],
407 &av1->yuvdata[2][chromaY * av1->yuvStride[2] + chromaX] };
409 aom_image_t buffer = WINPR_C_ARRAY_INIT;
411 aom_image_t* img = &buffer;
413#if defined(WITH_LIBYUV)
417 if ((SrcFormat == PIXEL_FORMAT_BGRA32) || (SrcFormat == PIXEL_FORMAT_BGRX32))
419 switch (av1->ecfg.g_profile)
422 img->fmt = AOM_IMG_FMT_I420;
423 img->x_chroma_shift = 1;
424 img->y_chroma_shift = 1;
425 rec = ARGBToI420(pSrc, nSrcStep, pDst[0], av1->yuvStride[0], pDst[1],
426 av1->yuvStride[1], pDst[2],
427 WINPR_ASSERTING_INT_CAST(
int, av1->yuvStride[2]),
428 WINPR_ASSERTING_INT_CAST(
int, roi.width),
429 WINPR_ASSERTING_INT_CAST(
int, roi.height));
432 img->fmt = AOM_IMG_FMT_I444;
433 rec = ARGBToI444(pSrc, nSrcStep, pDst[0], av1->yuvStride[0], pDst[1],
434 av1->yuvStride[1], pDst[2],
435 WINPR_ASSERTING_INT_CAST(
int, av1->yuvStride[2]),
436 WINPR_ASSERTING_INT_CAST(
int, roi.width),
437 WINPR_ASSERTING_INT_CAST(
int, roi.height));
440 WLog_Print(av1->log, WLOG_ERROR,
"Unsupoorted AV1 profile %" PRIu32,
441 av1->ecfg.g_profile);
448 switch (av1->ecfg.g_profile)
451 img->fmt = AOM_IMG_FMT_I420;
452 img->x_chroma_shift = 1;
453 img->y_chroma_shift = 1;
454 rec = primitives->RGBToYUV420_8u_P3AC4R(pSrc, SrcFormat, nSrcStep, pDst,
455 av1->yuvStride, &roi);
458 img->fmt = AOM_IMG_FMT_I444;
460 primitives->
RGBToI444_8u(pSrc, SrcFormat, nSrcStep, pDst, av1->yuvStride, &roi);
463 WLog_Print(av1->log, WLOG_ERROR,
"Unsupoorted AV1 profile %" PRIu32,
464 av1->ecfg.g_profile);
470 WLog_Print(av1->log, WLOG_ERROR,
"RGB to YUV conversion failed: %d", rec);
471 av1->fullFrameNext =
true;
474 av1->fullFrameNext =
false;
476 img->d_w = img->r_w = img->w = nSrcWidth;
477 img->d_h = img->r_h = img->h = nSrcHeight;
478 img->stride[0] = WINPR_ASSERTING_INT_CAST(
int, av1->yuvStride[0]);
479 img->stride[1] = WINPR_ASSERTING_INT_CAST(
int, av1->yuvStride[1]);
480 img->stride[2] = WINPR_ASSERTING_INT_CAST(
int, av1->yuvStride[2]);
481 img->planes[0] = av1->yuvdata[0];
482 img->planes[1] = av1->yuvdata[1];
483 img->planes[2] = av1->yuvdata[2];
485 const aom_codec_err_t rc = aom_codec_encode(&av1->ctx, img, ++av1->framecount, 1, av1->eflags);
488 if (rc != AOM_CODEC_OK)
490 WLog_Print(av1->log, WLOG_WARN,
"aom_codec_encode: %s", aom_codec_err_to_string(rc));
494 aom_codec_iter_t iter =
nullptr;
495 const aom_codec_cx_pkt_t* pkt =
nullptr;
496 while ((pkt = aom_codec_get_cx_data(&av1->ctx, &iter)) !=
nullptr)
498 if (pkt->kind != AOM_CODEC_CX_FRAME_PKT)
501 *ppDstData = pkt->data.frame.buf;
502 *pDstSize = pkt->data.frame.sz;
507 av1_encoder_stats(av1, startNS, *pDstSize);
512 rect->right = nSrcWidth;
513 rect->bottom = nSrcHeight;
515 return allocate_h264_metablock(10, rect, meta, 1);
517 WLog_Print(av1->log, WLOG_ERROR,
"AV1 encoder requires libaom, recompile with '-DWITH_AOM=ON'");
518 WINPR_UNUSED(pSrcData);
519 WINPR_UNUSED(SrcFormat);
520 WINPR_UNUSED(nSrcStep);
521 WINPR_UNUSED(nSrcWidth);
522 WINPR_UNUSED(nSrcHeight);
523 WINPR_UNUSED(regionRect);
529static BOOL isRectValid(UINT32 width, UINT32 height,
const RECTANGLE_16* rect)
532 if (rect->left > width)
534 if (rect->right > width)
536 if (rect->left >= rect->right)
538 if (rect->top > height)
540 if (rect->bottom > height)
542 if (rect->top >= rect->bottom)
547static BOOL areRectsValid(wLog* log, UINT32 width, UINT32 height,
const RECTANGLE_16* rects,
550 WINPR_ASSERT(rects || (count == 0));
551 for (
size_t x = 0; x < count; x++)
554 if (!isRectValid(width, height, rect))
556 char buffer[64] = WINPR_C_ARRAY_INIT;
557 WLog_Print(log, WLOG_WARN,
558 "Rectangle %" PRIuz
" %s outside of bounding frame %" PRIu32
"x%" PRIu32, x,
559 rectangle_to_string(rect, buffer,
sizeof(buffer)), width, height);
566#if defined(WITH_DAV1D)
567static void av1_dav1d_data_free(WINPR_ATTR_UNUSED
const uint8_t* buf,
568 WINPR_ATTR_UNUSED
void* cookie)
573static INT32 av1_dav1d_convert(FREERDP_AV1_CONTEXT* av1,
const Dav1dPicture* pic, BYTE* pDstData,
574 DWORD DstFormat, UINT32 nDstStep, UINT32 nDstWidth,
576 UINT32 numRegionRect)
580 WLog_Print(av1->log, WLOG_ERROR,
"dav1d picture bpc %d not supported", pic->p.bpc);
587 const UINT32 dw = (UINT32)pic->p.w;
588 const UINT32 dh = (UINT32)pic->p.h;
589 const UINT32 nWidth = (dw < nDstWidth) ? dw : nDstWidth;
590 const UINT32 nHeight = (dh < nDstHeight) ? dh : nDstHeight;
591 const prim_size_t roi = { .width = nWidth, .height = nHeight };
593 if (!areRectsValid(av1->log, roi.width, roi.height, regionRects, numRegionRect))
596 const UINT32 strides[] = { (UINT32)pic->stride[0], (UINT32)pic->stride[1],
597 (UINT32)pic->stride[1] };
600#if defined(WITH_LIBYUV)
604 if ((DstFormat == PIXEL_FORMAT_BGRA32) || (DstFormat == PIXEL_FORMAT_BGRX32))
606 const uint8_t* y = pic->data[0];
607 const uint8_t* u = pic->data[1];
608 const uint8_t* v = pic->data[2];
610 const int stride0 = WINPR_ASSERTING_INT_CAST(
int, strides[0]);
611 const int stride1 = WINPR_ASSERTING_INT_CAST(
int, strides[1]);
612 const int stride2 = WINPR_ASSERTING_INT_CAST(
int, strides[2]);
613 const int iWidth = WINPR_ASSERTING_INT_CAST(
int, nWidth);
614 const int iHeight = WINPR_ASSERTING_INT_CAST(
int, nHeight);
615 const int iDstStep = WINPR_ASSERTING_INT_CAST(
int, nDstStep);
617 switch (pic->p.layout)
619 case DAV1D_PIXEL_LAYOUT_I420:
620 rec = J420ToARGB(y, stride0, u, stride1, v, stride2, pDstData, iDstStep, iWidth,
623 case DAV1D_PIXEL_LAYOUT_I444:
624 rec = J444ToARGB(y, stride0, u, stride1, v, stride2, pDstData, iDstStep, iWidth,
628 WLog_Print(av1->log, WLOG_ERROR,
"dav1d picture layout %d not supported",
639 WLog_Print(av1->log, WLOG_ERROR,
"primitives_get(): nullptr");
643 const BYTE* pSrc[] = { pic->data[0], pic->data[1], pic->data[2] };
644 switch (pic->p.layout)
646 case DAV1D_PIXEL_LAYOUT_I420:
647 rec = primitives->YUV420ToRGB_8u_P3AC4R(pSrc, strides, pDstData, nDstStep,
650 case DAV1D_PIXEL_LAYOUT_I444:
651 rec = primitives->
I444ToRGB_8u(pSrc, strides, pDstData, nDstStep, DstFormat, &roi);
654 WLog_Print(av1->log, WLOG_ERROR,
"dav1d picture layout %d not supported",
661 WLog_Print(av1->log, WLOG_ERROR,
"RGB to YUV conversion failed: %d", rec);
668static INT32 av1_dav1d_drain_one(FREERDP_AV1_CONTEXT* av1, BYTE* pDstData, DWORD DstFormat,
669 UINT32 nDstStep, UINT32 nDstWidth, UINT32 nDstHeight,
672 Dav1dPicture pic = WINPR_C_ARRAY_INIT;
673 const int prc = dav1d_get_picture(av1->dav1d, &pic);
674 if (prc == DAV1D_ERR(EAGAIN))
678 WLog_Print(av1->log, WLOG_WARN,
"dav1d_get_picture: %d", prc);
682 const INT32 rc = av1_dav1d_convert(av1, &pic, pDstData, DstFormat, nDstStep, nDstWidth,
683 nDstHeight, regionRects, numRegionRect);
684 dav1d_picture_unref(&pic);
685 return (rc == TRUE) ? TRUE : rc;
689INT32 freerdp_av1_decompress(FREERDP_AV1_CONTEXT* av1,
const BYTE* pSrcData, UINT32 SrcSize,
690 BYTE* pDstData, DWORD DstFormat, UINT32 nDstStep, UINT32 nDstWidth,
692 UINT32 numRegionRect)
697 WLog_Print(av1->log, WLOG_ERROR,
"av1->encoder: %d", av1->encoder);
701 if (!areRectsValid(av1->log, nDstWidth, nDstHeight, regionRects, numRegionRect))
704#if defined(WITH_AV1_WEBCODECS)
705 if (av1->webcodecs > 0)
707 const INT32 wrc = av1_wc_decode(av1->webcodecs, pSrcData, SrcSize, pDstData, DstFormat,
708 nDstStep, nDstWidth, nDstHeight);
712 if (wrc == AV1_WC_UNSUPPORTED)
713 WLog_Print(av1->log, WLOG_DEBUG,
"surface format needs dav1d instead of WebCodecs");
715 WLog_Print(av1->log, WLOG_WARN,
716 "WebCodecs AV1 decode failed (%" PRId32
"), using dav1d", wrc);
717 av1_wc_close(av1->webcodecs);
722#if defined(WITH_DAV1D)
723 Dav1dData data = WINPR_C_ARRAY_INIT;
724 const int wrc = dav1d_data_wrap(&data, pSrcData, SrcSize, av1_dav1d_data_free,
nullptr);
727 WLog_Print(av1->log, WLOG_WARN,
"dav1d_data_wrap: %d", wrc);
733 const int src = dav1d_send_data(av1->dav1d, &data);
734 if ((src < 0) && (src != DAV1D_ERR(EAGAIN)))
736 WLog_Print(av1->log, WLOG_WARN,
"dav1d_send_data: %d", src);
737 dav1d_data_unref(&data);
741 const INT32 rc = av1_dav1d_drain_one(av1, pDstData, DstFormat, nDstStep, nDstWidth,
742 nDstHeight, regionRects, numRegionRect);
743 if ((rc != TRUE) && (rc != FALSE))
745 dav1d_data_unref(&data);
753 const INT32 rc = av1_dav1d_drain_one(av1, pDstData, DstFormat, nDstStep, nDstWidth,
754 nDstHeight, regionRects, numRegionRect);
762#elif defined(WITH_LIBAOM)
763 const aom_codec_err_t rc = aom_codec_decode(&av1->ctx, pSrcData, SrcSize,
nullptr);
764 if (rc != AOM_CODEC_OK)
766 WLog_Print(av1->log, WLOG_WARN,
"aom_codec_decode: %s", aom_codec_err_to_string(rc));
770 aom_image_t* img =
nullptr;
771 aom_codec_iter_t iter =
nullptr;
772 while ((img = aom_codec_get_frame(&av1->ctx, &iter)) !=
nullptr)
777 const UINT32 nWidth = (img->d_w < nDstWidth) ? img->d_w : nDstWidth;
778 const UINT32 nHeight = (img->d_h < nDstHeight) ? img->d_h : nDstHeight;
779 const prim_size_t roi = { .width = nWidth, .height = nHeight };
781 if (!areRectsValid(av1->log, roi.width, roi.height, regionRects, numRegionRect))
785#if defined(WITH_LIBYUV)
789 if ((DstFormat == PIXEL_FORMAT_BGRA32) || (DstFormat == PIXEL_FORMAT_BGRX32))
793 case AOM_IMG_FMT_I420:
794 rec = J420ToARGB(img->planes[0], img->stride[0], img->planes[1], img->stride[1],
795 img->planes[2], img->stride[2], pDstData, nDstStep, nWidth,
798 case AOM_IMG_FMT_I444:
799 rec = J444ToARGB(img->planes[0], img->stride[0], img->planes[1], img->stride[1],
800 img->planes[2], img->stride[2], pDstData, nDstStep, nWidth,
804 WLog_Print(av1->log, WLOG_ERROR,
"img->fmt %d not supported", img->fmt);
811 const BYTE* pSrc[] = { img->planes[0], img->planes[1], img->planes[2] };
812 const UINT32 strides[] = { img->stride[0], img->stride[1], img->stride[2] };
817 WLog_Print(av1->log, WLOG_ERROR,
"primitives_get(): nullptr");
823 case AOM_IMG_FMT_I420:
824 rec = primitives->YUV420ToRGB_8u_P3AC4R(pSrc, strides, pDstData, nDstStep,
827 case AOM_IMG_FMT_I444:
828 rec = primitives->
I444ToRGB_8u(pSrc, strides, pDstData, nDstStep, DstFormat,
832 WLog_Print(av1->log, WLOG_ERROR,
"img->fmt %d not supported", img->fmt);
838 WLog_Print(av1->log, WLOG_ERROR,
"RGB to YUV conversion failed: %d", rec);
847BOOL freerdp_av1_context_reset(FREERDP_AV1_CONTEXT* av1, UINT32 width, UINT32 height)
851#if defined(WITH_LIBAOM)
852 av1->ecfg.g_w = width;
853 av1->ecfg.g_h = height;
855 if (av1->initialized)
857 const aom_codec_err_t rc = aom_codec_destroy(&av1->ctx);
858 av1->initialized =
false;
859 if (rc != AOM_CODEC_OK)
861 WLog_Print(av1->log, WLOG_WARN,
"aom_codec_destroy: %s",
862 aom_codec_err_to_string(rc));
867 const aom_codec_err_t rc =
868 aom_codec_enc_init(&av1->ctx, av1->iface, &av1->ecfg, av1->flags);
869 if (rc != AOM_CODEC_OK)
871 WLog_Print(av1->log, WLOG_WARN,
"aom_codec_enc_init: %s", aom_codec_err_to_string(rc));
877 av1->initialized =
true;
878 av1->fullFrameNext =
true;
880 if (!av1_aom_apply_controls(av1))
883 WLog_Print(av1->log, WLOG_ERROR,
884 "AV1 encoder requires libaom, recompile with '-DWITH_AOM=ON'");
890#if defined(WITH_AV1_WEBCODECS)
891 if (av1->webcodecs == 0)
893 av1->webcodecs = av1_wc_open();
894 WLog_Print(av1->log, WLOG_INFO,
"AV1 decoder: %s",
895 av1->webcodecs > 0 ?
"WebCodecs (browser), dav1d as fallback" :
"dav1d");
898#if defined(WITH_DAV1D)
899 if (av1->initialized)
901 dav1d_close(&av1->dav1d);
902 av1->initialized =
false;
905 Dav1dSettings settings = WINPR_C_ARRAY_INIT;
906 dav1d_default_settings(&settings);
909 settings.n_threads = 1;
910 settings.max_frame_delay = 1;
912 const int rc = dav1d_open(&av1->dav1d, &settings);
915 WLog_Print(av1->log, WLOG_WARN,
"dav1d_open: %d", rc);
918 av1->initialized =
true;
919#elif defined(WITH_LIBAOM)
921 av1->dcfg.h = height;
922 av1->dcfg.allow_lowbitdepth = 1;
923 const aom_codec_err_t rc =
924 aom_codec_dec_init(&av1->ctx, av1->iface, &av1->dcfg, av1->flags);
925 if (rc != AOM_CODEC_OK)
927 WLog_Print(av1->log, WLOG_WARN,
"aom_codec_dec_init: %s", aom_codec_err_to_string(rc));
930 av1->initialized =
true;
932 WLog_Print(av1->log, WLOG_WARN,
933 "This build does not support AV1 decoding. Recompile with '-DWITH_DAV1D=ON' "
934 "or '-DWITH_AOM=ON'");
939 av1->yuvWidth = width;
940 av1->yuvStride[0] = width;
942 const size_t pad = av1->yuvStride[0] % 16;
944 av1->yuvStride[0] += 16 - pad;
945 av1->yuvStride[0] *= 3;
946 av1->yuvStride[1] = width;
947 av1->yuvStride[2] = width;
949 av1->yuvHeight = height;
950 winpr_aligned_free(av1->yuvdata[0]);
951 winpr_aligned_free(av1->yuvdata[1]);
952 winpr_aligned_free(av1->yuvdata[2]);
953 av1->yuvdata[0] = winpr_aligned_malloc(1ull * av1->yuvStride[0] * av1->yuvHeight, 64);
954 av1->yuvdata[1] = winpr_aligned_malloc(1ull * av1->yuvStride[1] * av1->yuvHeight, 64);
955 av1->yuvdata[2] = winpr_aligned_malloc(1ull * av1->yuvStride[2] * av1->yuvHeight, 64);
956 return av1->yuvdata[0] !=
nullptr;
959void freerdp_av1_context_free(FREERDP_AV1_CONTEXT* av1)
964 if (av1->initialized)
968#if defined(WITH_LIBAOM)
969 av1_aom_destroy(av1);
974#if defined(WITH_DAV1D)
975 dav1d_close(&av1->dav1d);
976#elif defined(WITH_LIBAOM)
977 av1_aom_destroy(av1);
981#if defined(WITH_AV1_WEBCODECS)
982 av1_wc_close(av1->webcodecs);
984 winpr_aligned_free(av1->yuvdata[0]);
985 winpr_aligned_free(av1->yuvdata[1]);
986 winpr_aligned_free(av1->yuvdata[2]);
990FREERDP_AV1_CONTEXT* freerdp_av1_context_new(BOOL Compressor)
992 FREERDP_AV1_CONTEXT* ctx = calloc(1,
sizeof(FREERDP_AV1_CONTEXT));
995 ctx->encoder = Compressor;
996 ctx->log = WLog_Get(TAG);
1002#if defined(WITH_LIBAOM)
1003 ctx->iface = aom_codec_av1_cx();
1006 WLog_Print(ctx->log, WLOG_ERROR,
"aom_codec_av1_cx() nullptr");
1010 const aom_codec_err_t rc =
1011 aom_codec_enc_config_default(ctx->iface, &ctx->ecfg, AOM_USAGE_REALTIME);
1012 if (rc != AOM_CODEC_OK)
1014 WLog_Print(ctx->log, WLOG_ERROR,
"aom_codec_enc_config_default() %s",
1015 aom_codec_err_to_string(rc));
1018 ctx->ecfg.g_threads = av1_aom_threads();
1020 WLog_Print(ctx->log, WLOG_ERROR,
1021 "AV1 encoder requires libaom, recompile with '-DWITH_AOM=ON'");
1025#if defined(WITH_LIBAOM) && !defined(WITH_DAV1D)
1028 ctx->iface = aom_codec_av1_dx();
1031 WLog_Print(ctx->log, WLOG_ERROR,
"aom_codec_av1_dx() nullptr");
1040 freerdp_av1_context_free(ctx);
1045struct S_FREERDP_AV1_CONTEXT
1051BOOL freerdp_av1_context_set_option(WINPR_ATTR_UNUSED FREERDP_AV1_CONTEXT* av1,
1052 WINPR_ATTR_UNUSED FREERDP_AV1_CONTEXT_OPTION option,
1053 WINPR_ATTR_UNUSED UINT32 value)
1058UINT32 freerdp_av1_context_get_option(WINPR_ATTR_UNUSED FREERDP_AV1_CONTEXT* av1,
1059 WINPR_ATTR_UNUSED FREERDP_AV1_CONTEXT_OPTION option)
1064INT32 freerdp_av1_compress(WINPR_ATTR_UNUSED FREERDP_AV1_CONTEXT* av1,
1065 WINPR_ATTR_UNUSED
const BYTE* pSrcData,
1066 WINPR_ATTR_UNUSED DWORD SrcFormat, WINPR_ATTR_UNUSED UINT32 nSrcStep,
1067 WINPR_ATTR_UNUSED UINT32 nSrcWidth, WINPR_ATTR_UNUSED UINT32 nSrcHeight,
1069 WINPR_ATTR_UNUSED BYTE** ppDstData, WINPR_ATTR_UNUSED UINT32* pDstSize,
1073 WLog_Print(av1->log, WLOG_ERROR,
1074 "This build does not support AV1 codec. Recompile with '-DWITH_AOM=ON' or "
1075 "'-DWITH_DAV1D=ON'");
1079INT32 freerdp_av1_decompress(WINPR_ATTR_UNUSED FREERDP_AV1_CONTEXT* av1,
1080 WINPR_ATTR_UNUSED
const BYTE* pSrcData,
1081 WINPR_ATTR_UNUSED UINT32 SrcSize, WINPR_ATTR_UNUSED BYTE* pDstData,
1082 WINPR_ATTR_UNUSED DWORD DstFormat, WINPR_ATTR_UNUSED UINT32 nDstStep,
1083 WINPR_ATTR_UNUSED UINT32 nDstWidth,
1084 WINPR_ATTR_UNUSED UINT32 nDstHeight,
1086 WINPR_ATTR_UNUSED UINT32 numRegionRect)
1089 WLog_Print(av1->log, WLOG_ERROR,
1090 "This build does not support AV1 codec. Recompile with '-DWITH_AOM=ON' or "
1091 "'-DWITH_DAV1D=ON'");
1095BOOL freerdp_av1_context_reset(WINPR_ATTR_UNUSED FREERDP_AV1_CONTEXT* av1,
1096 WINPR_ATTR_UNUSED UINT32 width, WINPR_ATTR_UNUSED UINT32 height)
1099 WLog_Print(av1->log, WLOG_WARN,
1100 "This build does not support AV1 codec. Recompile with '-DWITH_AOM=ON' or "
1101 "'-DWITH_DAV1D=ON'");
1105void freerdp_av1_context_free(WINPR_ATTR_UNUSED FREERDP_AV1_CONTEXT* av1)
1110FREERDP_AV1_CONTEXT* freerdp_av1_context_new(BOOL Compressor)
1112 FREERDP_AV1_CONTEXT* ctx = calloc(1,
sizeof(FREERDP_AV1_CONTEXT));
1115 ctx->Compressor = Compressor;
1116 ctx->log = WLog_Get(TAG);
WINPR_ATTR_NODISCARD fn_RGBToYUV444_8u_P3AC4R_t RGBToI444_8u
WINPR_ATTR_NODISCARD fn_YUV444ToRGB_8u_P3AC4R_t I444ToRGB_8u
Convert a plain YUV444 picture (e.g. decoded AV1) to RGB. Unlike YUV444ToRGB_8u_P3AC4R this does not ...