1#include <winpr/sysinfo.h>
2#include <winpr/assert.h>
6#include <freerdp/settings.h>
7#include <freerdp/codec/region.h>
8#include <freerdp/primitives.h>
9#include <freerdp/log.h>
10#include <freerdp/codec/yuv.h>
12#define TAG FREERDP_TAG("codec")
14#if !defined(YUV_TILE_SIZE)
15#error "YUV_TILE_SIZE must be defined to the size of a single YUV decoder block"
21 const BYTE* pYUVData[3];
27} YUV_PROCESS_WORK_PARAM;
32 const BYTE* pYUVData[3];
37 avc444_frame_type type;
38} YUV_COMBINE_WORK_PARAM;
50 BYTE* pYUVLumaData[3];
51 BYTE* pYUVChromaData[3];
53} YUV_ENCODE_WORK_PARAM;
62 UINT32 work_object_count;
63 PTP_WORK* work_objects;
64 YUV_ENCODE_WORK_PARAM* work_enc_params;
65 YUV_PROCESS_WORK_PARAM* work_dec_params;
66 YUV_COMBINE_WORK_PARAM* work_combined_params;
70static inline BOOL avc420_yuv_to_rgb(
const BYTE* WINPR_RESTRICT pYUVData[3],
71 const UINT32 iStride[3],
72 const RECTANGLE_16* WINPR_RESTRICT rect, UINT32 nDstStep,
73 BYTE* WINPR_RESTRICT pDstData, DWORD DstFormat)
77 const BYTE* pYUVPoint[3];
79 WINPR_ASSERT(pYUVData);
80 WINPR_ASSERT(iStride);
82 WINPR_ASSERT(pDstData);
84 const INT32 width = rect->right - rect->left;
85 const INT32 height = rect->bottom - rect->top;
86 BYTE* pDstPoint = pDstData + 1ULL * rect->top * nDstStep +
87 1ULL * rect->left * FreeRDPGetBytesPerPixel(DstFormat);
89 pYUVPoint[0] = pYUVData[0] + 1ULL * rect->top * iStride[0] + rect->left;
90 pYUVPoint[1] = pYUVData[1] + 1ULL * rect->top / 2 * iStride[1] + rect->left / 2;
91 pYUVPoint[2] = pYUVData[2] + 1ULL * rect->top / 2 * iStride[2] + rect->left / 2;
93 roi.width = WINPR_ASSERTING_INT_CAST(uint32_t, width);
94 roi.height = WINPR_ASSERTING_INT_CAST(uint32_t, height);
96 return (prims->YUV420ToRGB_8u_P3AC4R(pYUVPoint, iStride, pDstPoint, nDstStep, DstFormat,
97 &roi) == PRIMITIVES_SUCCESS);
101static inline BOOL avc444_yuv_to_rgb(
const BYTE* WINPR_RESTRICT pYUVData[3],
102 const UINT32 iStride[3],
103 const RECTANGLE_16* WINPR_RESTRICT rect, UINT32 nDstStep,
104 BYTE* WINPR_RESTRICT pDstData, DWORD DstFormat)
108 const BYTE* pYUVPoint[3];
110 WINPR_ASSERT(pYUVData);
111 WINPR_ASSERT(iStride);
113 WINPR_ASSERT(pDstData);
115 const INT32 width = rect->right - rect->left;
116 const INT32 height = rect->bottom - rect->top;
117 BYTE* pDstPoint = pDstData + 1ULL * rect->top * nDstStep +
118 1ULL * rect->left * FreeRDPGetBytesPerPixel(DstFormat);
120 pYUVPoint[0] = pYUVData[0] + 1ULL * rect->top * iStride[0] + rect->left;
121 pYUVPoint[1] = pYUVData[1] + 1ULL * rect->top * iStride[1] + rect->left;
122 pYUVPoint[2] = pYUVData[2] + 1ULL * rect->top * iStride[2] + rect->left;
124 roi.width = WINPR_ASSERTING_INT_CAST(uint32_t, width);
125 roi.height = WINPR_ASSERTING_INT_CAST(uint32_t, height);
127 return (prims->YUV444ToRGB_8u_P3AC4R(pYUVPoint, iStride, pDstPoint, nDstStep, DstFormat,
128 &roi) == PRIMITIVES_SUCCESS);
131static void CALLBACK yuv420_process_work_callback(PTP_CALLBACK_INSTANCE instance,
void* context,
134 YUV_PROCESS_WORK_PARAM* param = (YUV_PROCESS_WORK_PARAM*)context;
135 WINPR_UNUSED(instance);
139 if (!avc420_yuv_to_rgb(param->pYUVData, param->iStride, ¶m->rect, param->nDstStep,
140 param->dest, param->DstFormat))
141 WLog_WARN(TAG,
"avc420_yuv_to_rgb failed");
144static void CALLBACK yuv444_process_work_callback(PTP_CALLBACK_INSTANCE instance,
void* context,
147 YUV_PROCESS_WORK_PARAM* param = (YUV_PROCESS_WORK_PARAM*)context;
148 WINPR_UNUSED(instance);
152 if (!avc444_yuv_to_rgb(param->pYUVData, param->iStride, ¶m->rect, param->nDstStep,
153 param->dest, param->DstFormat))
154 WLog_WARN(TAG,
"avc444_yuv_to_rgb failed");
157BOOL yuv_context_reset(YUV_CONTEXT* WINPR_RESTRICT context, UINT32 width, UINT32 height)
160 WINPR_ASSERT(context);
162 if (width > UINT16_MAX)
164 WLog_ERR(TAG,
"YUV::width %" PRIu32
" > %d", width, UINT16_MAX);
168 if (height > UINT16_MAX)
170 WLog_ERR(TAG,
"YUV::height %" PRIu32
" > %d", height, UINT16_MAX);
174 context->width = width;
175 context->height = height;
177 context->heightStep = height;
179 if (context->useThreads)
181 context->heightStep = 16;
187 const size_t pw = (1ull * width + YUV_TILE_SIZE - width % YUV_TILE_SIZE) / 16;
188 const size_t ph = (1ull * height + YUV_TILE_SIZE - height % YUV_TILE_SIZE) / 16;
190 const size_t count = pw * ph;
192 context->work_object_count = 0;
193 if (context->encoder)
195 void* tmp = winpr_aligned_recalloc(context->work_enc_params, count,
196 sizeof(YUV_ENCODE_WORK_PARAM), 32);
199 memset(tmp, 0, count *
sizeof(YUV_ENCODE_WORK_PARAM));
201 context->work_enc_params = tmp;
205 void* tmp = winpr_aligned_recalloc(context->work_dec_params, count,
206 sizeof(YUV_PROCESS_WORK_PARAM), 32);
209 memset(tmp, 0, count *
sizeof(YUV_PROCESS_WORK_PARAM));
211 context->work_dec_params = tmp;
213 void* ctmp = winpr_aligned_recalloc(context->work_combined_params, count,
214 sizeof(YUV_COMBINE_WORK_PARAM), 32);
217 memset(ctmp, 0, count *
sizeof(YUV_COMBINE_WORK_PARAM));
219 context->work_combined_params = ctmp;
223 winpr_aligned_recalloc((
void*)context->work_objects, count,
sizeof(PTP_WORK), 32);
226 memset(wtmp, 0, count *
sizeof(PTP_WORK));
228 context->work_objects = (PTP_WORK*)wtmp;
229 context->work_object_count = WINPR_ASSERTING_INT_CAST(uint32_t, count);
236YUV_CONTEXT* yuv_context_new(BOOL encoder, UINT32 ThreadingFlags)
240 if (!primitives_get())
243 YUV_CONTEXT* ret = winpr_aligned_calloc(1,
sizeof(*ret), 32);
247 ret->encoder = encoder;
248 if (!(ThreadingFlags & THREADING_FLAGS_DISABLE_THREADS))
250 GetNativeSystemInfo(&sysInfos);
251 ret->useThreads = (sysInfos.dwNumberOfProcessors > 1);
257void yuv_context_free(YUV_CONTEXT* context)
261 if (context->useThreads)
263 winpr_aligned_free((
void*)context->work_objects);
264 winpr_aligned_free(context->work_combined_params);
265 winpr_aligned_free(context->work_enc_params);
266 winpr_aligned_free(context->work_dec_params);
268 winpr_aligned_free(context);
272static inline YUV_PROCESS_WORK_PARAM pool_decode_param(
const RECTANGLE_16* WINPR_RESTRICT rect,
273 YUV_CONTEXT* WINPR_RESTRICT context,
274 const BYTE* WINPR_RESTRICT pYUVData[3],
275 const UINT32 iStride[3], UINT32 DstFormat,
276 BYTE* WINPR_RESTRICT dest, UINT32 nDstStep)
278 YUV_PROCESS_WORK_PARAM current = WINPR_C_ARRAY_INIT;
281 WINPR_ASSERT(context);
282 WINPR_ASSERT(pYUVData);
283 WINPR_ASSERT(iStride);
286 current.context = context;
287 current.DstFormat = DstFormat;
288 current.pYUVData[0] = pYUVData[0];
289 current.pYUVData[1] = pYUVData[1];
290 current.pYUVData[2] = pYUVData[2];
291 current.iStride[0] = iStride[0];
292 current.iStride[1] = iStride[1];
293 current.iStride[2] = iStride[2];
294 current.nDstStep = nDstStep;
296 current.rect = *rect;
301static BOOL submit_object(PTP_WORK* WINPR_RESTRICT work_object, PTP_WORK_CALLBACK cb,
302 const void* WINPR_RESTRICT param, YUV_CONTEXT* WINPR_RESTRICT context)
315 *work_object =
nullptr;
317 if (!param || !context)
320 *work_object = CreateThreadpoolWork(cb, cnv.pv,
nullptr);
324 SubmitThreadpoolWork(*work_object);
328static void free_objects(PTP_WORK* work_objects, UINT32 waitCount)
330 WINPR_ASSERT(work_objects || (waitCount == 0));
332 for (UINT32 i = 0; i < waitCount; i++)
334 PTP_WORK cur = work_objects[i];
335 work_objects[i] =
nullptr;
340 WaitForThreadpoolWorkCallbacks(cur, FALSE);
341 CloseThreadpoolWork(cur);
346static BOOL intersects(UINT32 pos,
const RECTANGLE_16* WINPR_RESTRICT regionRects,
347 UINT32 numRegionRects)
349 WINPR_ASSERT(regionRects || (numRegionRects == 0));
351 for (UINT32 x = pos + 1; x < numRegionRects; x++)
356 if (rectangles_intersects(what, rect))
358 WLog_WARN(TAG,
"YUV decoder: intersecting rectangles, aborting");
367static RECTANGLE_16 clamp(YUV_CONTEXT* WINPR_RESTRICT context,
368 const RECTANGLE_16* WINPR_RESTRICT rect, UINT32 srcHeight)
370 WINPR_ASSERT(context);
374 const UINT32 height = MIN(context->height, srcHeight);
376 c.top = WINPR_ASSERTING_INT_CAST(UINT16, height);
377 if (c.bottom > height)
378 c.bottom = WINPR_ASSERTING_INT_CAST(UINT16, height);
383static BOOL pool_decode(YUV_CONTEXT* WINPR_RESTRICT context, PTP_WORK_CALLBACK cb,
384 const BYTE* WINPR_RESTRICT pYUVData[3],
const UINT32 iStride[3],
385 UINT32 yuvHeight, UINT32 DstFormat, BYTE* WINPR_RESTRICT dest,
386 UINT32 nDstStep,
const RECTANGLE_16* WINPR_RESTRICT regionRects,
387 UINT32 numRegionRects)
390 UINT32 waitCount = 0;
393 WINPR_ASSERT(context);
395 WINPR_ASSERT(pYUVData);
396 WINPR_ASSERT(iStride);
398 WINPR_ASSERT(regionRects || (numRegionRects == 0));
400 if (context->encoder)
402 WLog_ERR(TAG,
"YUV context set up for encoding, can not decode with it, aborting");
406 if (!context->useThreads || (primitives_flags(prims) & PRIM_FLAGS_HAVE_EXTGPU))
408 for (UINT32 y = 0; y < numRegionRects; y++)
410 const RECTANGLE_16 rect = clamp(context, ®ionRects[y], yuvHeight);
411 YUV_PROCESS_WORK_PARAM current =
412 pool_decode_param(&rect, context, pYUVData, iStride, DstFormat, dest, nDstStep);
413 cb(
nullptr, ¤t,
nullptr);
419 for (UINT32 x = 0; x < numRegionRects; x++)
421 RECTANGLE_16 r = clamp(context, ®ionRects[x], yuvHeight);
423 if (intersects(x, regionRects, numRegionRects))
426 while (r.left < r.right)
429 y.right = MIN(r.right, r.left + YUV_TILE_SIZE);
431 while (y.top < y.bottom)
435 if (context->work_object_count <= waitCount)
437 free_objects(context->work_objects, context->work_object_count);
441 YUV_PROCESS_WORK_PARAM* cur = &context->work_dec_params[waitCount];
442 z.bottom = MIN(z.bottom, z.top + YUV_TILE_SIZE);
443 if (rectangle_is_empty(&z))
445 *cur = pool_decode_param(&z, context, pYUVData, iStride, DstFormat, dest, nDstStep);
446 if (!submit_object(&context->work_objects[waitCount], cb, cur, context))
449 y.top += YUV_TILE_SIZE;
452 r.left += YUV_TILE_SIZE;
457 free_objects(context->work_objects, context->work_object_count);
462static inline BOOL check_rect(
const YUV_CONTEXT* WINPR_RESTRICT yuv,
463 const RECTANGLE_16* WINPR_RESTRICT rect, UINT32 nDstWidth,
470 if ((rect->right > yuv->width) || (rect->left > yuv->width))
473 if ((rect->top > yuv->height) || (rect->bottom > yuv->height))
477 if ((rect->right > nDstWidth) || (rect->left > nDstWidth))
480 if ((rect->bottom > nDstHeight) || (rect->top > nDstHeight))
486static void CALLBACK yuv444_combine_work_callback(PTP_CALLBACK_INSTANCE instance,
void* context,
489 YUV_COMBINE_WORK_PARAM* param = (YUV_COMBINE_WORK_PARAM*)context;
493 YUV_CONTEXT* yuv = param->context;
503 const UINT32 alignedWidth =
504 MIN(yuv->width + ((yuv->width % 32 != 0) ? 32 - yuv->width % 32 : 0), param->iStride[0]);
505 const UINT32 alignedHeight =
506 yuv->height + ((yuv->height % 16 != 0) ? 16 - yuv->height % 16 : 0);
508 WINPR_UNUSED(instance);
511 if (!check_rect(param->context, rect, yuv->width, yuv->height))
514 if (prims->YUV420CombineToYUV444(param->type, param->pYUVData, param->iStride, alignedWidth,
515 alignedHeight, param->pYUVDstData, param->iDstStride,
516 rect) != PRIMITIVES_SUCCESS)
517 WLog_WARN(TAG,
"YUV420CombineToYUV444 failed");
521static inline YUV_COMBINE_WORK_PARAM
522pool_decode_rect_param(
const RECTANGLE_16* WINPR_RESTRICT rect, YUV_CONTEXT* WINPR_RESTRICT context,
523 BYTE type,
const BYTE* WINPR_RESTRICT pYUVData[3],
const UINT32 iStride[3],
524 BYTE* WINPR_RESTRICT pYUVDstData[3],
const UINT32 iDstStride[3])
526 YUV_COMBINE_WORK_PARAM current = WINPR_C_ARRAY_INIT;
529 WINPR_ASSERT(context);
530 WINPR_ASSERT(pYUVData);
531 WINPR_ASSERT(iStride);
532 WINPR_ASSERT(pYUVDstData);
533 WINPR_ASSERT(iDstStride);
535 current.context = context;
536 current.pYUVData[0] = pYUVData[0];
537 current.pYUVData[1] = pYUVData[1];
538 current.pYUVData[2] = pYUVData[2];
539 current.pYUVDstData[0] = pYUVDstData[0];
540 current.pYUVDstData[1] = pYUVDstData[1];
541 current.pYUVDstData[2] = pYUVDstData[2];
542 current.iStride[0] = iStride[0];
543 current.iStride[1] = iStride[1];
544 current.iStride[2] = iStride[2];
545 current.iDstStride[0] = iDstStride[0];
546 current.iDstStride[1] = iDstStride[1];
547 current.iDstStride[2] = iDstStride[2];
548 current.type = WINPR_ASSERTING_INT_CAST(avc444_frame_type, type);
549 current.rect = *rect;
554static BOOL pool_decode_rect(YUV_CONTEXT* WINPR_RESTRICT context, BYTE type,
555 const BYTE* WINPR_RESTRICT pYUVData[3],
const UINT32 iStride[3],
556 BYTE* WINPR_RESTRICT pYUVDstData[3],
const UINT32 iDstStride[3],
557 const RECTANGLE_16* WINPR_RESTRICT regionRects, UINT32 numRegionRects)
560 UINT32 waitCount = 0;
561 PTP_WORK_CALLBACK cb = yuv444_combine_work_callback;
564 WINPR_ASSERT(context);
565 WINPR_ASSERT(pYUVData);
566 WINPR_ASSERT(iStride);
567 WINPR_ASSERT(pYUVDstData);
568 WINPR_ASSERT(iDstStride);
569 WINPR_ASSERT(regionRects || (numRegionRects == 0));
571 if (!context->useThreads || (primitives_flags(prims) & PRIM_FLAGS_HAVE_EXTGPU))
573 for (UINT32 y = 0; y < numRegionRects; y++)
575 YUV_COMBINE_WORK_PARAM current = pool_decode_rect_param(
576 ®ionRects[y], context, type, pYUVData, iStride, pYUVDstData, iDstStride);
577 cb(
nullptr, ¤t,
nullptr);
583 for (UINT32 x = 0; x < numRegionRects; x++)
585 YUV_COMBINE_WORK_PARAM* current =
nullptr;
587 if (context->work_object_count <= waitCount)
589 free_objects(context->work_objects, context->work_object_count);
592 current = &context->work_combined_params[waitCount];
593 *current = pool_decode_rect_param(®ionRects[x], context, type, pYUVData, iStride,
594 pYUVDstData, iDstStride);
596 if (!submit_object(&context->work_objects[waitCount], cb, current, context))
603 free_objects(context->work_objects, context->work_object_count);
607BOOL yuv444_context_decode(YUV_CONTEXT* WINPR_RESTRICT context, BYTE type,
608 const BYTE* WINPR_RESTRICT pYUVData[3],
const UINT32 iStride[3],
609 UINT32 srcYuvHeight, BYTE* WINPR_RESTRICT pYUVDstData[3],
610 const UINT32 iDstStride[3], DWORD DstFormat, BYTE* WINPR_RESTRICT dest,
611 UINT32 nDstStep,
const RECTANGLE_16* WINPR_RESTRICT regionRects,
612 UINT32 numRegionRects)
614 const BYTE* pYUVCDstData[3];
616 WINPR_ASSERT(context);
617 WINPR_ASSERT(pYUVData);
618 WINPR_ASSERT(iStride);
619 WINPR_ASSERT(pYUVDstData);
620 WINPR_ASSERT(iDstStride);
622 WINPR_ASSERT(regionRects || (numRegionRects == 0));
624 if (context->encoder)
626 WLog_ERR(TAG,
"YUV context set up for encoding, can not decode with it, aborting");
629 if (!pool_decode_rect(context, type, pYUVData, iStride, pYUVDstData, iDstStride, regionRects,
633 pYUVCDstData[0] = pYUVDstData[0];
634 pYUVCDstData[1] = pYUVDstData[1];
635 pYUVCDstData[2] = pYUVDstData[2];
636 return pool_decode(context, yuv444_process_work_callback, pYUVCDstData, iDstStride,
637 srcYuvHeight, DstFormat, dest, nDstStep, regionRects, numRegionRects);
640BOOL yuv420_context_decode(YUV_CONTEXT* WINPR_RESTRICT context,
641 const BYTE* WINPR_RESTRICT pYUVData[3],
const UINT32 iStride[3],
642 UINT32 yuvHeight, DWORD DstFormat, BYTE* WINPR_RESTRICT dest,
643 UINT32 nDstStep,
const RECTANGLE_16* WINPR_RESTRICT regionRects,
644 UINT32 numRegionRects)
646 return pool_decode(context, yuv420_process_work_callback, pYUVData, iStride, yuvHeight,
647 DstFormat, dest, nDstStep, regionRects, numRegionRects);
650static void CALLBACK yuv420_encode_work_callback(PTP_CALLBACK_INSTANCE instance,
void* context,
654 YUV_ENCODE_WORK_PARAM* param = (YUV_ENCODE_WORK_PARAM*)context;
657 const BYTE* src =
nullptr;
659 WINPR_UNUSED(instance);
663 roi.width = param->rect.right - param->rect.left;
664 roi.height = param->rect.bottom - param->rect.top;
665 src = param->pSrcData + 1ULL * param->nSrcStep * param->rect.top +
666 1ULL * param->rect.left * FreeRDPGetBytesPerPixel(param->SrcFormat);
668 param->pYUVLumaData[0] + 1ULL * param->rect.top * param->iStride[0] + param->rect.left;
669 pYUVData[1] = param->pYUVLumaData[1] + 1ULL * param->rect.top / 2 * param->iStride[1] +
670 param->rect.left / 2;
671 pYUVData[2] = param->pYUVLumaData[2] + 1ULL * param->rect.top / 2 * param->iStride[2] +
672 param->rect.left / 2;
674 if (prims->RGBToYUV420_8u_P3AC4R(src, param->SrcFormat, param->nSrcStep, pYUVData,
675 param->iStride, &roi) != PRIMITIVES_SUCCESS)
677 WLog_ERR(TAG,
"error when decoding lines");
681static void CALLBACK yuv444v1_encode_work_callback(PTP_CALLBACK_INSTANCE instance,
void* context,
685 YUV_ENCODE_WORK_PARAM* param = (YUV_ENCODE_WORK_PARAM*)context;
687 BYTE* pYUVLumaData[3] = WINPR_C_ARRAY_INIT;
688 BYTE* pYUVChromaData[3] = WINPR_C_ARRAY_INIT;
689 const BYTE* src =
nullptr;
691 WINPR_UNUSED(instance);
695 roi.width = param->rect.right - param->rect.left;
696 roi.height = param->rect.bottom - param->rect.top;
698 const size_t offset = 1ULL * param->nSrcStep * param->rect.top +
699 1ULL * param->rect.left * FreeRDPGetBytesPerPixel(param->SrcFormat);
700 src = ¶m->pSrcData[offset];
703 const size_t offset = 1ULL * param->rect.top * param->iStride[0] + param->rect.left;
704 pYUVLumaData[0] = ¶m->pYUVLumaData[0][offset];
707 const size_t offset = 1ULL * param->rect.top / 2 * param->iStride[1] + param->rect.left / 2;
708 pYUVLumaData[1] = ¶m->pYUVLumaData[1][offset];
711 const size_t offset = 1ULL * param->rect.top / 2 * param->iStride[2] + param->rect.left / 2;
712 pYUVLumaData[2] = ¶m->pYUVLumaData[2][offset];
715 const size_t offset = 1ULL * param->rect.top * param->iStride[0] + param->rect.left;
716 pYUVChromaData[0] = ¶m->pYUVChromaData[0][offset];
719 const size_t offset = 1ULL * param->rect.top / 2 * param->iStride[1] + param->rect.left / 2;
720 pYUVChromaData[1] = ¶m->pYUVChromaData[1][offset];
723 const size_t offset = 1ULL * param->rect.top / 2 * param->iStride[2] + param->rect.left / 2;
724 pYUVChromaData[2] = ¶m->pYUVChromaData[2][offset];
726 if (prims->RGBToAVC444YUV(src, param->SrcFormat, param->nSrcStep, pYUVLumaData, param->iStride,
727 pYUVChromaData, param->iStride, &roi) != PRIMITIVES_SUCCESS)
729 WLog_ERR(TAG,
"error when decoding lines");
733static void CALLBACK yuv444v2_encode_work_callback(PTP_CALLBACK_INSTANCE instance,
void* context,
737 YUV_ENCODE_WORK_PARAM* param = (YUV_ENCODE_WORK_PARAM*)context;
739 BYTE* pYUVLumaData[3];
740 BYTE* pYUVChromaData[3];
741 const BYTE* src =
nullptr;
743 WINPR_UNUSED(instance);
747 roi.width = param->rect.right - param->rect.left;
748 roi.height = param->rect.bottom - param->rect.top;
750 const size_t offset = 1ULL * param->nSrcStep * param->rect.top +
751 1ULL * param->rect.left * FreeRDPGetBytesPerPixel(param->SrcFormat);
752 src = ¶m->pSrcData[offset];
755 const size_t offset = 1ULL * param->rect.top * param->iStride[0] + param->rect.left;
756 pYUVLumaData[0] = ¶m->pYUVLumaData[0][offset];
759 const size_t offset = 1ULL * param->rect.top / 2 * param->iStride[1] + param->rect.left / 2;
760 pYUVLumaData[1] = ¶m->pYUVLumaData[1][offset];
763 const size_t offset = 1ULL * param->rect.top / 2 * param->iStride[2] + param->rect.left / 2;
764 pYUVLumaData[2] = ¶m->pYUVLumaData[2][offset];
767 const size_t offset = 1ULL * param->rect.top * param->iStride[0] + param->rect.left;
768 pYUVChromaData[0] = ¶m->pYUVChromaData[0][offset];
771 const size_t offset = 1ULL * param->rect.top / 2 * param->iStride[1] + param->rect.left / 2;
772 pYUVChromaData[1] = ¶m->pYUVChromaData[1][offset];
775 const size_t offset = 1ULL * param->rect.top / 2 * param->iStride[2] + param->rect.left / 2;
776 pYUVChromaData[2] = ¶m->pYUVChromaData[2][offset];
778 if (prims->RGBToAVC444YUVv2(src, param->SrcFormat, param->nSrcStep, pYUVLumaData,
779 param->iStride, pYUVChromaData, param->iStride,
780 &roi) != PRIMITIVES_SUCCESS)
782 WLog_ERR(TAG,
"error when decoding lines");
787static inline YUV_ENCODE_WORK_PARAM
788pool_encode_fill(
const RECTANGLE_16* WINPR_RESTRICT rect, YUV_CONTEXT* WINPR_RESTRICT context,
789 const BYTE* WINPR_RESTRICT pSrcData, UINT32 nSrcStep, UINT32 SrcFormat,
790 const UINT32 iStride[], BYTE* WINPR_RESTRICT pYUVLumaData[],
791 BYTE* WINPR_RESTRICT pYUVChromaData[])
793 YUV_ENCODE_WORK_PARAM current = WINPR_C_ARRAY_INIT;
796 WINPR_ASSERT(context);
797 WINPR_ASSERT(pSrcData);
798 WINPR_ASSERT(iStride);
799 WINPR_ASSERT(pYUVLumaData);
801 current.context = context;
802 current.pSrcData = pSrcData;
803 current.SrcFormat = SrcFormat;
804 current.nSrcStep = nSrcStep;
805 current.pYUVLumaData[0] = pYUVLumaData[0];
806 current.pYUVLumaData[1] = pYUVLumaData[1];
807 current.pYUVLumaData[2] = pYUVLumaData[2];
810 current.pYUVChromaData[0] = pYUVChromaData[0];
811 current.pYUVChromaData[1] = pYUVChromaData[1];
812 current.pYUVChromaData[2] = pYUVChromaData[2];
814 current.iStride[0] = iStride[0];
815 current.iStride[1] = iStride[1];
816 current.iStride[2] = iStride[2];
818 current.rect = *rect;
824static uint32_t getSteps(uint32_t height, uint32_t step)
826 const uint32_t steps = (height + step / 2 + 1) / step;
833static BOOL pool_encode(YUV_CONTEXT* WINPR_RESTRICT context, PTP_WORK_CALLBACK cb,
834 const BYTE* WINPR_RESTRICT pSrcData, UINT32 nSrcStep, UINT32 SrcFormat,
835 const UINT32 iStride[], BYTE* WINPR_RESTRICT pYUVLumaData[],
836 BYTE* WINPR_RESTRICT pYUVChromaData[],
837 const RECTANGLE_16* WINPR_RESTRICT regionRects, UINT32 numRegionRects)
841 UINT32 waitCount = 0;
843 WINPR_ASSERT(context);
845 WINPR_ASSERT(pSrcData);
846 WINPR_ASSERT(iStride);
847 WINPR_ASSERT(regionRects || (numRegionRects == 0));
849 if (!context->encoder)
852 WLog_ERR(TAG,
"YUV context set up for decoding, can not encode with it, aborting");
856 if (!context->useThreads || (primitives_flags(prims) & PRIM_FLAGS_HAVE_EXTGPU))
858 for (UINT32 x = 0; x < numRegionRects; x++)
860 YUV_ENCODE_WORK_PARAM current =
861 pool_encode_fill(®ionRects[x], context, pSrcData, nSrcStep, SrcFormat, iStride,
862 pYUVLumaData, pYUVChromaData);
863 cb(
nullptr, ¤t,
nullptr);
869 for (UINT32 x = 0; x < numRegionRects; x++)
872 const UINT32 height = rect->bottom - rect->top;
873 const UINT32 steps = getSteps(height, context->heightStep);
875 for (UINT32 y = 0; y < steps; y++)
878 YUV_ENCODE_WORK_PARAM* current =
nullptr;
880 if (context->work_object_count <= waitCount)
882 free_objects(context->work_objects, context->work_object_count);
886 current = &context->work_enc_params[waitCount];
887 r.top += y * context->heightStep;
894 r.bottom = (UINT16)MIN((UINT32)rect->bottom, (UINT32)r.top + context->heightStep);
895 *current = pool_encode_fill(&r, context, pSrcData, nSrcStep, SrcFormat, iStride,
896 pYUVLumaData, pYUVChromaData);
897 if (!submit_object(&context->work_objects[waitCount], cb, current, context))
905 free_objects(context->work_objects, context->work_object_count);
909BOOL yuv420_context_encode(YUV_CONTEXT* WINPR_RESTRICT context,
const BYTE* WINPR_RESTRICT pSrcData,
910 UINT32 nSrcStep, UINT32 SrcFormat,
const UINT32 iStride[3],
911 BYTE* WINPR_RESTRICT pYUVData[3],
912 const RECTANGLE_16* WINPR_RESTRICT regionRects, UINT32 numRegionRects)
914 if (!context || !pSrcData || !iStride || !pYUVData || !regionRects)
917 return pool_encode(context, yuv420_encode_work_callback, pSrcData, nSrcStep, SrcFormat, iStride,
918 pYUVData,
nullptr, regionRects, numRegionRects);
921BOOL yuv444_context_encode(YUV_CONTEXT* WINPR_RESTRICT context, BYTE version,
922 const BYTE* WINPR_RESTRICT pSrcData, UINT32 nSrcStep, UINT32 SrcFormat,
923 const UINT32 iStride[3], BYTE* WINPR_RESTRICT pYUVLumaData[3],
924 BYTE* WINPR_RESTRICT pYUVChromaData[3],
925 const RECTANGLE_16* WINPR_RESTRICT regionRects, UINT32 numRegionRects)
927 PTP_WORK_CALLBACK cb =
nullptr;
931 cb = yuv444v1_encode_work_callback;
934 cb = yuv444v2_encode_work_callback;
940 return pool_encode(context, cb, pSrcData, nSrcStep, SrcFormat, iStride, pYUVLumaData,
941 pYUVChromaData, regionRects, numRegionRects);