2017-12-15 13:15:24 +03:00
|
|
|
|
#include <winpr/sysinfo.h>
|
2022-03-29 14:55:52 +03:00
|
|
|
|
#include <winpr/assert.h>
|
2017-12-15 13:15:24 +03:00
|
|
|
|
#include <winpr/pool.h>
|
|
|
|
|
|
2023-03-14 12:39:18 +03:00
|
|
|
|
#include <freerdp/settings.h>
|
|
|
|
|
#include <freerdp/codec/region.h>
|
2017-12-15 13:15:24 +03:00
|
|
|
|
#include <freerdp/primitives.h>
|
|
|
|
|
#include <freerdp/log.h>
|
|
|
|
|
#include <freerdp/codec/yuv.h>
|
|
|
|
|
|
|
|
|
|
#define TAG FREERDP_TAG("codec")
|
|
|
|
|
|
2022-03-29 14:55:52 +03:00
|
|
|
|
#define TILE_SIZE 64
|
2017-12-15 13:15:24 +03:00
|
|
|
|
|
2022-02-14 16:59:22 +03:00
|
|
|
|
typedef struct
|
2017-12-15 13:15:24 +03:00
|
|
|
|
{
|
|
|
|
|
YUV_CONTEXT* context;
|
|
|
|
|
const BYTE* pYUVData[3];
|
|
|
|
|
UINT32 iStride[3];
|
|
|
|
|
DWORD DstFormat;
|
2019-11-06 17:24:51 +03:00
|
|
|
|
BYTE* dest;
|
2017-12-15 13:15:24 +03:00
|
|
|
|
UINT32 nDstStep;
|
2020-10-22 19:11:21 +03:00
|
|
|
|
RECTANGLE_16 rect;
|
2022-02-14 16:59:22 +03:00
|
|
|
|
} YUV_PROCESS_WORK_PARAM;
|
2017-12-15 13:15:24 +03:00
|
|
|
|
|
2022-02-14 16:59:22 +03:00
|
|
|
|
typedef struct
|
2020-10-22 19:11:21 +03:00
|
|
|
|
{
|
|
|
|
|
YUV_CONTEXT* context;
|
|
|
|
|
const BYTE* pYUVData[3];
|
|
|
|
|
UINT32 iStride[3];
|
|
|
|
|
BYTE* pYUVDstData[3];
|
|
|
|
|
UINT32 iDstStride[3];
|
|
|
|
|
RECTANGLE_16 rect;
|
|
|
|
|
BYTE type;
|
2022-02-14 16:59:22 +03:00
|
|
|
|
} YUV_COMBINE_WORK_PARAM;
|
2020-10-22 19:11:21 +03:00
|
|
|
|
|
2022-02-14 16:59:22 +03:00
|
|
|
|
typedef struct
|
2020-10-22 19:11:21 +03:00
|
|
|
|
{
|
|
|
|
|
YUV_CONTEXT* context;
|
|
|
|
|
const BYTE* pSrcData;
|
|
|
|
|
|
|
|
|
|
DWORD SrcFormat;
|
|
|
|
|
UINT32 nSrcStep;
|
|
|
|
|
RECTANGLE_16 rect;
|
|
|
|
|
BYTE version;
|
|
|
|
|
|
|
|
|
|
BYTE* pYUVLumaData[3];
|
|
|
|
|
BYTE* pYUVChromaData[3];
|
|
|
|
|
UINT32 iStride[3];
|
2022-02-14 16:59:22 +03:00
|
|
|
|
} YUV_ENCODE_WORK_PARAM;
|
2020-10-22 19:11:21 +03:00
|
|
|
|
|
2022-03-29 14:55:52 +03:00
|
|
|
|
struct S_YUV_CONTEXT
|
|
|
|
|
{
|
|
|
|
|
UINT32 width, height;
|
|
|
|
|
BOOL useThreads;
|
|
|
|
|
BOOL encoder;
|
|
|
|
|
UINT32 nthreads;
|
|
|
|
|
UINT32 heightStep;
|
|
|
|
|
|
|
|
|
|
PTP_POOL threadPool;
|
|
|
|
|
TP_CALLBACK_ENVIRON ThreadPoolEnv;
|
|
|
|
|
|
|
|
|
|
UINT32 work_object_count;
|
|
|
|
|
PTP_WORK* work_objects;
|
|
|
|
|
YUV_ENCODE_WORK_PARAM* work_enc_params;
|
|
|
|
|
YUV_PROCESS_WORK_PARAM* work_dec_params;
|
|
|
|
|
YUV_COMBINE_WORK_PARAM* work_combined_params;
|
|
|
|
|
};
|
|
|
|
|
|
2024-05-30 00:44:47 +03:00
|
|
|
|
static INLINE BOOL avc420_yuv_to_rgb(const BYTE* WINPR_RESTRICT pYUVData[3],
|
|
|
|
|
const UINT32 iStride[3],
|
|
|
|
|
const RECTANGLE_16* WINPR_RESTRICT rect, UINT32 nDstStep,
|
|
|
|
|
BYTE* WINPR_RESTRICT pDstData, DWORD DstFormat)
|
2021-04-02 13:10:15 +03:00
|
|
|
|
{
|
|
|
|
|
primitives_t* prims = primitives_get();
|
|
|
|
|
prim_size_t roi;
|
|
|
|
|
const BYTE* pYUVPoint[3];
|
2022-03-29 14:55:52 +03:00
|
|
|
|
|
|
|
|
|
WINPR_ASSERT(pYUVData);
|
|
|
|
|
WINPR_ASSERT(iStride);
|
|
|
|
|
WINPR_ASSERT(rect);
|
|
|
|
|
WINPR_ASSERT(pDstData);
|
|
|
|
|
|
2021-04-02 13:10:15 +03:00
|
|
|
|
const INT32 width = rect->right - rect->left;
|
|
|
|
|
const INT32 height = rect->bottom - rect->top;
|
2022-04-28 06:43:31 +03:00
|
|
|
|
BYTE* pDstPoint =
|
|
|
|
|
pDstData + rect->top * nDstStep + rect->left * FreeRDPGetBytesPerPixel(DstFormat);
|
2021-04-02 13:10:15 +03:00
|
|
|
|
|
|
|
|
|
pYUVPoint[0] = pYUVData[0] + rect->top * iStride[0] + rect->left;
|
|
|
|
|
pYUVPoint[1] = pYUVData[1] + rect->top / 2 * iStride[1] + rect->left / 2;
|
|
|
|
|
pYUVPoint[2] = pYUVData[2] + rect->top / 2 * iStride[2] + rect->left / 2;
|
|
|
|
|
|
|
|
|
|
roi.width = width;
|
|
|
|
|
roi.height = height;
|
|
|
|
|
|
|
|
|
|
if (prims->YUV420ToRGB_8u_P3AC4R(pYUVPoint, iStride, pDstPoint, nDstStep, DstFormat, &roi) !=
|
|
|
|
|
PRIMITIVES_SUCCESS)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-30 00:44:47 +03:00
|
|
|
|
static INLINE BOOL avc444_yuv_to_rgb(const BYTE* WINPR_RESTRICT pYUVData[3],
|
|
|
|
|
const UINT32 iStride[3],
|
|
|
|
|
const RECTANGLE_16* WINPR_RESTRICT rect, UINT32 nDstStep,
|
|
|
|
|
BYTE* WINPR_RESTRICT pDstData, DWORD DstFormat)
|
2021-04-02 13:10:15 +03:00
|
|
|
|
{
|
|
|
|
|
primitives_t* prims = primitives_get();
|
|
|
|
|
prim_size_t roi;
|
|
|
|
|
const BYTE* pYUVPoint[3];
|
2022-03-29 14:55:52 +03:00
|
|
|
|
|
|
|
|
|
WINPR_ASSERT(pYUVData);
|
|
|
|
|
WINPR_ASSERT(iStride);
|
|
|
|
|
WINPR_ASSERT(rect);
|
|
|
|
|
WINPR_ASSERT(pDstData);
|
|
|
|
|
|
2021-04-02 13:10:15 +03:00
|
|
|
|
const INT32 width = rect->right - rect->left;
|
|
|
|
|
const INT32 height = rect->bottom - rect->top;
|
2022-04-28 06:43:31 +03:00
|
|
|
|
BYTE* pDstPoint =
|
|
|
|
|
pDstData + rect->top * nDstStep + rect->left * FreeRDPGetBytesPerPixel(DstFormat);
|
2021-04-02 13:10:15 +03:00
|
|
|
|
|
|
|
|
|
pYUVPoint[0] = pYUVData[0] + rect->top * iStride[0] + rect->left;
|
|
|
|
|
pYUVPoint[1] = pYUVData[1] + rect->top * iStride[1] + rect->left;
|
|
|
|
|
pYUVPoint[2] = pYUVData[2] + rect->top * iStride[2] + rect->left;
|
|
|
|
|
|
|
|
|
|
roi.width = width;
|
|
|
|
|
roi.height = height;
|
|
|
|
|
|
|
|
|
|
if (prims->YUV444ToRGB_8u_P3AC4R(pYUVPoint, iStride, pDstPoint, nDstStep, DstFormat, &roi) !=
|
|
|
|
|
PRIMITIVES_SUCCESS)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-22 19:11:21 +03:00
|
|
|
|
static void CALLBACK yuv420_process_work_callback(PTP_CALLBACK_INSTANCE instance, void* context,
|
|
|
|
|
PTP_WORK work)
|
|
|
|
|
{
|
|
|
|
|
YUV_PROCESS_WORK_PARAM* param = (YUV_PROCESS_WORK_PARAM*)context;
|
2021-04-02 13:10:15 +03:00
|
|
|
|
WINPR_UNUSED(instance);
|
|
|
|
|
WINPR_UNUSED(work);
|
2022-03-29 14:55:52 +03:00
|
|
|
|
WINPR_ASSERT(param);
|
2020-10-22 19:11:21 +03:00
|
|
|
|
|
2021-04-06 09:59:36 +03:00
|
|
|
|
if (!avc420_yuv_to_rgb(param->pYUVData, param->iStride, ¶m->rect, param->nDstStep,
|
|
|
|
|
param->dest, param->DstFormat))
|
|
|
|
|
WLog_WARN(TAG, "avc420_yuv_to_rgb failed");
|
2020-10-22 19:11:21 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void CALLBACK yuv444_process_work_callback(PTP_CALLBACK_INSTANCE instance, void* context,
|
|
|
|
|
PTP_WORK work)
|
2017-12-15 13:15:24 +03:00
|
|
|
|
{
|
|
|
|
|
YUV_PROCESS_WORK_PARAM* param = (YUV_PROCESS_WORK_PARAM*)context;
|
2021-04-02 13:10:15 +03:00
|
|
|
|
WINPR_UNUSED(instance);
|
|
|
|
|
WINPR_UNUSED(work);
|
2022-03-29 14:55:52 +03:00
|
|
|
|
WINPR_ASSERT(param);
|
2017-12-15 13:15:24 +03:00
|
|
|
|
|
2021-04-06 09:59:36 +03:00
|
|
|
|
if (!avc444_yuv_to_rgb(param->pYUVData, param->iStride, ¶m->rect, param->nDstStep,
|
|
|
|
|
param->dest, param->DstFormat))
|
|
|
|
|
WLog_WARN(TAG, "avc444_yuv_to_rgb failed");
|
2017-12-15 13:15:24 +03:00
|
|
|
|
}
|
|
|
|
|
|
2024-05-30 00:44:47 +03:00
|
|
|
|
BOOL yuv_context_reset(YUV_CONTEXT* WINPR_RESTRICT context, UINT32 width, UINT32 height)
|
2017-12-15 13:15:24 +03:00
|
|
|
|
{
|
2023-05-22 12:17:02 +03:00
|
|
|
|
BOOL rc = FALSE;
|
2022-03-29 14:55:52 +03:00
|
|
|
|
WINPR_ASSERT(context);
|
|
|
|
|
|
2017-12-15 13:15:24 +03:00
|
|
|
|
context->width = width;
|
|
|
|
|
context->height = height;
|
|
|
|
|
context->heightStep = (height / context->nthreads);
|
2022-03-29 14:55:52 +03:00
|
|
|
|
|
|
|
|
|
if (context->useThreads)
|
|
|
|
|
{
|
2022-10-18 10:51:09 +03:00
|
|
|
|
const UINT32 pw = (width + TILE_SIZE - width % TILE_SIZE) / TILE_SIZE;
|
|
|
|
|
const UINT32 ph = (height + TILE_SIZE - height % TILE_SIZE) / TILE_SIZE;
|
|
|
|
|
|
|
|
|
|
/* We´ve calculated the amount of workers for 64x64 tiles, but the decoder
|
|
|
|
|
* might get 16x16 tiles mixed in. */
|
|
|
|
|
const UINT32 count = pw * ph * 16;
|
2022-03-29 14:55:52 +03:00
|
|
|
|
|
|
|
|
|
context->work_object_count = 0;
|
|
|
|
|
if (context->encoder)
|
|
|
|
|
{
|
2023-03-24 14:48:58 +03:00
|
|
|
|
void* tmp = winpr_aligned_recalloc(context->work_enc_params, count,
|
|
|
|
|
sizeof(YUV_ENCODE_WORK_PARAM), 32);
|
|
|
|
|
if (!tmp)
|
2023-05-22 12:17:02 +03:00
|
|
|
|
goto fail;
|
|
|
|
|
memset(tmp, 0, count * sizeof(YUV_ENCODE_WORK_PARAM));
|
|
|
|
|
|
2023-03-24 14:48:58 +03:00
|
|
|
|
context->work_enc_params = tmp;
|
2022-03-29 14:55:52 +03:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2023-03-24 14:48:58 +03:00
|
|
|
|
void* tmp = winpr_aligned_recalloc(context->work_dec_params, count,
|
|
|
|
|
sizeof(YUV_PROCESS_WORK_PARAM), 32);
|
|
|
|
|
if (!tmp)
|
2023-05-22 12:17:02 +03:00
|
|
|
|
goto fail;
|
|
|
|
|
memset(tmp, 0, count * sizeof(YUV_PROCESS_WORK_PARAM));
|
2022-03-29 14:55:52 +03:00
|
|
|
|
|
2023-03-24 14:48:58 +03:00
|
|
|
|
context->work_dec_params = tmp;
|
|
|
|
|
|
|
|
|
|
void* ctmp = winpr_aligned_recalloc(context->work_combined_params, count,
|
|
|
|
|
sizeof(YUV_COMBINE_WORK_PARAM), 32);
|
|
|
|
|
if (!ctmp)
|
2023-05-22 12:17:02 +03:00
|
|
|
|
goto fail;
|
|
|
|
|
memset(ctmp, 0, count * sizeof(YUV_COMBINE_WORK_PARAM));
|
|
|
|
|
|
2023-03-24 14:48:58 +03:00
|
|
|
|
context->work_combined_params = ctmp;
|
2022-03-29 14:55:52 +03:00
|
|
|
|
}
|
|
|
|
|
|
2023-03-24 14:48:58 +03:00
|
|
|
|
void* wtmp = winpr_aligned_recalloc(context->work_objects, count, sizeof(PTP_WORK), 32);
|
|
|
|
|
if (!wtmp)
|
2023-05-22 12:17:02 +03:00
|
|
|
|
goto fail;
|
|
|
|
|
memset(wtmp, 0, count * sizeof(PTP_WORK));
|
2022-03-29 14:55:52 +03:00
|
|
|
|
|
2023-03-24 14:48:58 +03:00
|
|
|
|
context->work_objects = wtmp;
|
2022-03-29 14:55:52 +03:00
|
|
|
|
context->work_object_count = count;
|
|
|
|
|
}
|
2023-05-22 12:17:02 +03:00
|
|
|
|
rc = TRUE;
|
|
|
|
|
fail:
|
|
|
|
|
return rc;
|
2017-12-15 13:15:24 +03:00
|
|
|
|
}
|
|
|
|
|
|
2021-03-12 18:54:45 +03:00
|
|
|
|
YUV_CONTEXT* yuv_context_new(BOOL encoder, UINT32 ThreadingFlags)
|
2017-12-15 13:15:24 +03:00
|
|
|
|
{
|
|
|
|
|
SYSTEM_INFO sysInfos;
|
2023-03-24 14:48:58 +03:00
|
|
|
|
YUV_CONTEXT* ret = winpr_aligned_calloc(1, sizeof(*ret), 32);
|
2017-12-15 13:15:24 +03:00
|
|
|
|
if (!ret)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
/** do it here to avoid a race condition between threads */
|
|
|
|
|
primitives_get();
|
|
|
|
|
|
2022-03-29 14:55:52 +03:00
|
|
|
|
ret->encoder = encoder;
|
2021-03-12 18:54:45 +03:00
|
|
|
|
ret->nthreads = 1;
|
|
|
|
|
if (!(ThreadingFlags & THREADING_FLAGS_DISABLE_THREADS))
|
2017-12-15 13:15:24 +03:00
|
|
|
|
{
|
2021-03-12 18:54:45 +03:00
|
|
|
|
GetNativeSystemInfo(&sysInfos);
|
|
|
|
|
ret->useThreads = (sysInfos.dwNumberOfProcessors > 1);
|
|
|
|
|
if (ret->useThreads)
|
2017-12-15 13:15:24 +03:00
|
|
|
|
{
|
2021-03-12 18:54:45 +03:00
|
|
|
|
ret->nthreads = sysInfos.dwNumberOfProcessors;
|
|
|
|
|
ret->threadPool = CreateThreadpool(NULL);
|
|
|
|
|
if (!ret->threadPool)
|
|
|
|
|
{
|
|
|
|
|
goto error_threadpool;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
InitializeThreadpoolEnvironment(&ret->ThreadPoolEnv);
|
|
|
|
|
SetThreadpoolCallbackPool(&ret->ThreadPoolEnv, ret->threadPool);
|
2020-12-15 18:11:22 +03:00
|
|
|
|
}
|
2017-12-15 13:15:24 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
|
|
error_threadpool:
|
2024-04-17 10:20:29 +03:00
|
|
|
|
WINPR_PRAGMA_DIAG_PUSH
|
|
|
|
|
WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
|
2020-10-22 19:11:21 +03:00
|
|
|
|
yuv_context_free(ret);
|
2024-04-17 10:20:29 +03:00
|
|
|
|
WINPR_PRAGMA_DIAG_POP
|
2017-12-15 13:15:24 +03:00
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void yuv_context_free(YUV_CONTEXT* context)
|
|
|
|
|
{
|
2020-10-22 19:11:21 +03:00
|
|
|
|
if (!context)
|
|
|
|
|
return;
|
2017-12-15 13:15:24 +03:00
|
|
|
|
if (context->useThreads)
|
|
|
|
|
{
|
2021-09-07 14:39:50 +03:00
|
|
|
|
if (context->threadPool)
|
|
|
|
|
CloseThreadpool(context->threadPool);
|
2017-12-15 13:15:24 +03:00
|
|
|
|
DestroyThreadpoolEnvironment(&context->ThreadPoolEnv);
|
2023-03-24 14:48:58 +03:00
|
|
|
|
winpr_aligned_free(context->work_objects);
|
|
|
|
|
winpr_aligned_free(context->work_combined_params);
|
|
|
|
|
winpr_aligned_free(context->work_enc_params);
|
|
|
|
|
winpr_aligned_free(context->work_dec_params);
|
2017-12-15 13:15:24 +03:00
|
|
|
|
}
|
2023-03-24 14:48:58 +03:00
|
|
|
|
winpr_aligned_free(context);
|
2017-12-15 13:15:24 +03:00
|
|
|
|
}
|
|
|
|
|
|
2024-05-30 00:44:47 +03:00
|
|
|
|
static INLINE YUV_PROCESS_WORK_PARAM pool_decode_param(const RECTANGLE_16* WINPR_RESTRICT rect,
|
|
|
|
|
YUV_CONTEXT* WINPR_RESTRICT context,
|
|
|
|
|
const BYTE* WINPR_RESTRICT pYUVData[3],
|
2020-10-22 19:11:21 +03:00
|
|
|
|
const UINT32 iStride[3], UINT32 DstFormat,
|
2024-05-30 00:44:47 +03:00
|
|
|
|
BYTE* WINPR_RESTRICT dest, UINT32 nDstStep)
|
2020-10-22 19:11:21 +03:00
|
|
|
|
{
|
|
|
|
|
YUV_PROCESS_WORK_PARAM current = { 0 };
|
|
|
|
|
|
2022-03-29 14:55:52 +03:00
|
|
|
|
WINPR_ASSERT(rect);
|
|
|
|
|
WINPR_ASSERT(context);
|
|
|
|
|
WINPR_ASSERT(pYUVData);
|
|
|
|
|
WINPR_ASSERT(iStride);
|
|
|
|
|
WINPR_ASSERT(dest);
|
|
|
|
|
|
2020-10-22 19:11:21 +03:00
|
|
|
|
current.context = context;
|
|
|
|
|
current.DstFormat = DstFormat;
|
|
|
|
|
current.pYUVData[0] = pYUVData[0];
|
|
|
|
|
current.pYUVData[1] = pYUVData[1];
|
|
|
|
|
current.pYUVData[2] = pYUVData[2];
|
|
|
|
|
current.iStride[0] = iStride[0];
|
|
|
|
|
current.iStride[1] = iStride[1];
|
|
|
|
|
current.iStride[2] = iStride[2];
|
|
|
|
|
current.nDstStep = nDstStep;
|
|
|
|
|
current.dest = dest;
|
|
|
|
|
current.rect = *rect;
|
|
|
|
|
return current;
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-30 00:44:47 +03:00
|
|
|
|
static BOOL submit_object(PTP_WORK* WINPR_RESTRICT work_object, PTP_WORK_CALLBACK cb,
|
|
|
|
|
const void* WINPR_RESTRICT param, YUV_CONTEXT* WINPR_RESTRICT context)
|
2020-10-22 19:11:21 +03:00
|
|
|
|
{
|
2022-04-27 22:02:18 +03:00
|
|
|
|
union
|
|
|
|
|
{
|
|
|
|
|
const void* cpv;
|
|
|
|
|
void* pv;
|
|
|
|
|
} cnv;
|
|
|
|
|
|
|
|
|
|
cnv.cpv = param;
|
|
|
|
|
|
2023-05-22 12:17:02 +03:00
|
|
|
|
if (!work_object)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
*work_object = NULL;
|
|
|
|
|
|
|
|
|
|
if (!param || !context)
|
2020-10-22 19:11:21 +03:00
|
|
|
|
return FALSE;
|
|
|
|
|
|
2022-04-27 22:02:18 +03:00
|
|
|
|
*work_object = CreateThreadpoolWork(cb, cnv.pv, &context->ThreadPoolEnv);
|
2020-10-22 19:11:21 +03:00
|
|
|
|
if (!*work_object)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
SubmitThreadpoolWork(*work_object);
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-29 14:55:52 +03:00
|
|
|
|
static void free_objects(PTP_WORK* work_objects, UINT32 waitCount)
|
2020-10-22 19:11:21 +03:00
|
|
|
|
{
|
2022-06-23 08:57:38 +03:00
|
|
|
|
WINPR_ASSERT(work_objects || (waitCount == 0));
|
2022-03-29 14:55:52 +03:00
|
|
|
|
|
2024-01-30 12:25:38 +03:00
|
|
|
|
for (UINT32 i = 0; i < waitCount; i++)
|
2022-06-23 08:57:38 +03:00
|
|
|
|
{
|
|
|
|
|
PTP_WORK cur = work_objects[i];
|
|
|
|
|
work_objects[i] = NULL;
|
2022-03-29 14:55:52 +03:00
|
|
|
|
|
2022-06-23 08:57:38 +03:00
|
|
|
|
if (!cur)
|
|
|
|
|
continue;
|
2022-03-29 14:55:52 +03:00
|
|
|
|
|
2022-06-23 08:57:38 +03:00
|
|
|
|
WaitForThreadpoolWorkCallbacks(cur, FALSE);
|
|
|
|
|
CloseThreadpoolWork(cur);
|
|
|
|
|
}
|
2022-03-29 14:55:52 +03:00
|
|
|
|
}
|
|
|
|
|
|
2024-05-30 00:44:47 +03:00
|
|
|
|
static BOOL intersects(UINT32 pos, const RECTANGLE_16* WINPR_RESTRICT regionRects,
|
|
|
|
|
UINT32 numRegionRects)
|
2022-03-29 14:55:52 +03:00
|
|
|
|
{
|
|
|
|
|
WINPR_ASSERT(regionRects || (numRegionRects == 0));
|
|
|
|
|
|
2024-01-30 12:25:38 +03:00
|
|
|
|
for (UINT32 x = pos + 1; x < numRegionRects; x++)
|
2022-03-29 14:55:52 +03:00
|
|
|
|
{
|
|
|
|
|
const RECTANGLE_16* what = ®ionRects[pos];
|
|
|
|
|
const RECTANGLE_16* rect = ®ionRects[x];
|
|
|
|
|
|
|
|
|
|
if (rectangles_intersects(what, rect))
|
|
|
|
|
{
|
|
|
|
|
WLog_WARN(TAG, "YUV decoder: intersecting rectangles, aborting");
|
|
|
|
|
return TRUE;
|
2020-11-20 14:37:21 +03:00
|
|
|
|
}
|
2020-10-22 19:11:21 +03:00
|
|
|
|
}
|
|
|
|
|
|
2022-03-29 14:55:52 +03:00
|
|
|
|
return FALSE;
|
2020-10-22 19:11:21 +03:00
|
|
|
|
}
|
|
|
|
|
|
2024-05-30 00:44:47 +03:00
|
|
|
|
static RECTANGLE_16 clamp(YUV_CONTEXT* WINPR_RESTRICT context,
|
|
|
|
|
const RECTANGLE_16* WINPR_RESTRICT rect, UINT32 srcHeight)
|
2023-08-23 09:42:53 +03:00
|
|
|
|
{
|
|
|
|
|
WINPR_ASSERT(context);
|
|
|
|
|
WINPR_ASSERT(rect);
|
|
|
|
|
|
|
|
|
|
RECTANGLE_16 c = *rect;
|
|
|
|
|
const UINT32 height = MIN(context->height, srcHeight);
|
|
|
|
|
if (c.top > height)
|
|
|
|
|
c.top = height;
|
|
|
|
|
if (c.bottom > height)
|
|
|
|
|
c.bottom = height;
|
|
|
|
|
return c;
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-30 00:44:47 +03:00
|
|
|
|
static BOOL pool_decode(YUV_CONTEXT* WINPR_RESTRICT context, PTP_WORK_CALLBACK cb,
|
|
|
|
|
const BYTE* WINPR_RESTRICT pYUVData[3], const UINT32 iStride[3],
|
|
|
|
|
UINT32 yuvHeight, UINT32 DstFormat, BYTE* WINPR_RESTRICT dest,
|
|
|
|
|
UINT32 nDstStep, const RECTANGLE_16* WINPR_RESTRICT regionRects,
|
|
|
|
|
UINT32 numRegionRects)
|
2017-12-15 13:15:24 +03:00
|
|
|
|
{
|
2020-10-22 19:11:21 +03:00
|
|
|
|
BOOL rc = FALSE;
|
2022-03-29 14:55:52 +03:00
|
|
|
|
UINT32 waitCount = 0;
|
2018-01-29 18:20:59 +03:00
|
|
|
|
primitives_t* prims = primitives_get();
|
2017-12-15 13:15:24 +03:00
|
|
|
|
|
2022-03-29 14:55:52 +03:00
|
|
|
|
WINPR_ASSERT(context);
|
|
|
|
|
WINPR_ASSERT(cb);
|
|
|
|
|
WINPR_ASSERT(pYUVData);
|
|
|
|
|
WINPR_ASSERT(iStride);
|
|
|
|
|
WINPR_ASSERT(dest);
|
|
|
|
|
WINPR_ASSERT(regionRects || (numRegionRects == 0));
|
|
|
|
|
|
|
|
|
|
if (context->encoder)
|
|
|
|
|
{
|
|
|
|
|
WLog_ERR(TAG, "YUV context set up for encoding, can not decode with it, aborting");
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-02 13:15:03 +03:00
|
|
|
|
if (!context->useThreads || (primitives_flags(prims) & PRIM_FLAGS_HAVE_EXTGPU))
|
2017-12-15 13:15:24 +03:00
|
|
|
|
{
|
2022-06-30 11:15:45 +03:00
|
|
|
|
for (UINT32 y = 0; y < numRegionRects; y++)
|
2020-10-22 19:11:21 +03:00
|
|
|
|
{
|
2023-08-23 09:42:53 +03:00
|
|
|
|
const RECTANGLE_16 rect = clamp(context, ®ionRects[y], yuvHeight);
|
2021-03-03 16:06:01 +03:00
|
|
|
|
YUV_PROCESS_WORK_PARAM current =
|
2023-08-23 09:42:53 +03:00
|
|
|
|
pool_decode_param(&rect, context, pYUVData, iStride, DstFormat, dest, nDstStep);
|
2020-10-22 19:11:21 +03:00
|
|
|
|
cb(NULL, ¤t, NULL);
|
|
|
|
|
}
|
|
|
|
|
return TRUE;
|
2017-12-15 13:15:24 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* case where we use threads */
|
2024-01-30 12:25:38 +03:00
|
|
|
|
for (UINT32 x = 0; x < numRegionRects; x++)
|
2020-11-20 14:37:21 +03:00
|
|
|
|
{
|
2023-08-23 09:42:53 +03:00
|
|
|
|
RECTANGLE_16 r = clamp(context, ®ionRects[x], yuvHeight);
|
2021-03-03 16:06:01 +03:00
|
|
|
|
|
2022-03-29 14:55:52 +03:00
|
|
|
|
if (intersects(x, regionRects, numRegionRects))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
while (r.left < r.right)
|
2020-10-22 19:11:21 +03:00
|
|
|
|
{
|
2022-03-29 14:55:52 +03:00
|
|
|
|
RECTANGLE_16 y = r;
|
|
|
|
|
y.right = MIN(r.right, r.left + TILE_SIZE);
|
|
|
|
|
|
|
|
|
|
while (y.top < y.bottom)
|
|
|
|
|
{
|
|
|
|
|
RECTANGLE_16 z = y;
|
|
|
|
|
|
|
|
|
|
if (context->work_object_count <= waitCount)
|
|
|
|
|
{
|
2022-10-18 10:51:09 +03:00
|
|
|
|
WLog_ERR(TAG,
|
2023-08-23 09:42:53 +03:00
|
|
|
|
"YUV decoder: invalid number of tiles, only support less than %" PRIu32
|
2022-10-18 10:51:09 +03:00
|
|
|
|
", got %" PRIu32,
|
|
|
|
|
context->work_object_count, waitCount);
|
2022-03-29 14:55:52 +03:00
|
|
|
|
goto fail;
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-23 09:42:53 +03:00
|
|
|
|
YUV_PROCESS_WORK_PARAM* cur = &context->work_dec_params[waitCount];
|
2022-03-29 14:55:52 +03:00
|
|
|
|
z.bottom = MIN(z.bottom, z.top + TILE_SIZE);
|
|
|
|
|
if (rectangle_is_empty(&z))
|
|
|
|
|
continue;
|
|
|
|
|
*cur = pool_decode_param(&z, context, pYUVData, iStride, DstFormat, dest, nDstStep);
|
|
|
|
|
if (!submit_object(&context->work_objects[waitCount], cb, cur, context))
|
|
|
|
|
goto fail;
|
|
|
|
|
waitCount++;
|
|
|
|
|
y.top += TILE_SIZE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
r.left += TILE_SIZE;
|
2020-10-22 19:11:21 +03:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
rc = TRUE;
|
|
|
|
|
fail:
|
2023-05-22 12:17:02 +03:00
|
|
|
|
free_objects(context->work_objects, context->work_object_count);
|
2020-10-22 19:11:21 +03:00
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-30 00:44:47 +03:00
|
|
|
|
static INLINE BOOL check_rect(const YUV_CONTEXT* WINPR_RESTRICT yuv,
|
|
|
|
|
const RECTANGLE_16* WINPR_RESTRICT rect, UINT32 nDstWidth,
|
2020-10-22 19:11:21 +03:00
|
|
|
|
UINT32 nDstHeight)
|
|
|
|
|
{
|
2022-03-29 14:55:52 +03:00
|
|
|
|
WINPR_ASSERT(yuv);
|
|
|
|
|
WINPR_ASSERT(rect);
|
|
|
|
|
|
2020-10-22 19:11:21 +03:00
|
|
|
|
/* Check, if the output rectangle is valid in decoded h264 frame. */
|
|
|
|
|
if ((rect->right > yuv->width) || (rect->left > yuv->width))
|
|
|
|
|
return FALSE;
|
2021-03-12 18:54:45 +03:00
|
|
|
|
|
2020-10-22 19:11:21 +03:00
|
|
|
|
if ((rect->top > yuv->height) || (rect->bottom > yuv->height))
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
/* Check, if the output rectangle is valid in destination buffer. */
|
|
|
|
|
if ((rect->right > nDstWidth) || (rect->left > nDstWidth))
|
2017-12-15 13:15:24 +03:00
|
|
|
|
return FALSE;
|
2020-10-22 19:11:21 +03:00
|
|
|
|
|
|
|
|
|
if ((rect->bottom > nDstHeight) || (rect->top > nDstHeight))
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void CALLBACK yuv444_combine_work_callback(PTP_CALLBACK_INSTANCE instance, void* context,
|
|
|
|
|
PTP_WORK work)
|
|
|
|
|
{
|
|
|
|
|
YUV_COMBINE_WORK_PARAM* param = (YUV_COMBINE_WORK_PARAM*)context;
|
|
|
|
|
primitives_t* prims = primitives_get();
|
2022-03-29 14:55:52 +03:00
|
|
|
|
|
|
|
|
|
WINPR_ASSERT(param);
|
2020-10-22 19:11:21 +03:00
|
|
|
|
YUV_CONTEXT* yuv = param->context;
|
2022-03-29 14:55:52 +03:00
|
|
|
|
WINPR_ASSERT(yuv);
|
|
|
|
|
|
2020-10-22 19:11:21 +03:00
|
|
|
|
const RECTANGLE_16* rect = ¶m->rect;
|
2022-03-29 14:55:52 +03:00
|
|
|
|
WINPR_ASSERT(rect);
|
|
|
|
|
|
2020-10-22 19:11:21 +03:00
|
|
|
|
const UINT32 alignedWidth = yuv->width + ((yuv->width % 16 != 0) ? 16 - yuv->width % 16 : 0);
|
|
|
|
|
const UINT32 alignedHeight =
|
|
|
|
|
yuv->height + ((yuv->height % 16 != 0) ? 16 - yuv->height % 16 : 0);
|
|
|
|
|
|
|
|
|
|
WINPR_UNUSED(instance);
|
|
|
|
|
WINPR_UNUSED(work);
|
|
|
|
|
|
2021-03-05 17:25:07 +03:00
|
|
|
|
if (!check_rect(param->context, rect, yuv->width, yuv->height))
|
2020-10-22 19:11:21 +03:00
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (prims->YUV420CombineToYUV444(param->type, param->pYUVData, param->iStride, alignedWidth,
|
|
|
|
|
alignedHeight, param->pYUVDstData, param->iDstStride,
|
|
|
|
|
rect) != PRIMITIVES_SUCCESS)
|
|
|
|
|
WLog_WARN(TAG, "YUV420CombineToYUV444 failed");
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-30 00:44:47 +03:00
|
|
|
|
static INLINE YUV_COMBINE_WORK_PARAM
|
|
|
|
|
pool_decode_rect_param(const RECTANGLE_16* WINPR_RESTRICT rect, YUV_CONTEXT* WINPR_RESTRICT context,
|
|
|
|
|
BYTE type, const BYTE* WINPR_RESTRICT pYUVData[3], const UINT32 iStride[3],
|
|
|
|
|
BYTE* WINPR_RESTRICT pYUVDstData[3], const UINT32 iDstStride[3])
|
2020-10-22 19:11:21 +03:00
|
|
|
|
{
|
|
|
|
|
YUV_COMBINE_WORK_PARAM current = { 0 };
|
2022-03-29 14:55:52 +03:00
|
|
|
|
|
|
|
|
|
WINPR_ASSERT(rect);
|
|
|
|
|
WINPR_ASSERT(context);
|
|
|
|
|
WINPR_ASSERT(pYUVData);
|
|
|
|
|
WINPR_ASSERT(iStride);
|
|
|
|
|
WINPR_ASSERT(pYUVDstData);
|
|
|
|
|
WINPR_ASSERT(iDstStride);
|
|
|
|
|
|
2020-10-22 19:11:21 +03:00
|
|
|
|
current.context = context;
|
|
|
|
|
current.pYUVData[0] = pYUVData[0];
|
|
|
|
|
current.pYUVData[1] = pYUVData[1];
|
|
|
|
|
current.pYUVData[2] = pYUVData[2];
|
|
|
|
|
current.pYUVDstData[0] = pYUVDstData[0];
|
|
|
|
|
current.pYUVDstData[1] = pYUVDstData[1];
|
|
|
|
|
current.pYUVDstData[2] = pYUVDstData[2];
|
|
|
|
|
current.iStride[0] = iStride[0];
|
|
|
|
|
current.iStride[1] = iStride[1];
|
|
|
|
|
current.iStride[2] = iStride[2];
|
|
|
|
|
current.iDstStride[0] = iDstStride[0];
|
|
|
|
|
current.iDstStride[1] = iDstStride[1];
|
|
|
|
|
current.iDstStride[2] = iDstStride[2];
|
|
|
|
|
current.type = type;
|
|
|
|
|
current.rect = *rect;
|
|
|
|
|
return current;
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-30 00:44:47 +03:00
|
|
|
|
static BOOL pool_decode_rect(YUV_CONTEXT* WINPR_RESTRICT context, BYTE type,
|
|
|
|
|
const BYTE* WINPR_RESTRICT pYUVData[3], const UINT32 iStride[3],
|
|
|
|
|
BYTE* WINPR_RESTRICT pYUVDstData[3], const UINT32 iDstStride[3],
|
|
|
|
|
const RECTANGLE_16* WINPR_RESTRICT regionRects, UINT32 numRegionRects)
|
2020-10-22 19:11:21 +03:00
|
|
|
|
{
|
|
|
|
|
BOOL rc = FALSE;
|
|
|
|
|
UINT32 waitCount = 0;
|
|
|
|
|
PTP_WORK_CALLBACK cb = yuv444_combine_work_callback;
|
|
|
|
|
primitives_t* prims = primitives_get();
|
|
|
|
|
|
2022-03-29 14:55:52 +03:00
|
|
|
|
WINPR_ASSERT(context);
|
|
|
|
|
WINPR_ASSERT(pYUVData);
|
|
|
|
|
WINPR_ASSERT(iStride);
|
|
|
|
|
WINPR_ASSERT(pYUVDstData);
|
|
|
|
|
WINPR_ASSERT(iDstStride);
|
|
|
|
|
WINPR_ASSERT(regionRects || (numRegionRects == 0));
|
|
|
|
|
|
2020-10-22 19:11:21 +03:00
|
|
|
|
if (!context->useThreads || (primitives_flags(prims) & PRIM_FLAGS_HAVE_EXTGPU))
|
|
|
|
|
{
|
2024-01-30 12:25:38 +03:00
|
|
|
|
for (UINT32 y = 0; y < numRegionRects; y++)
|
2020-10-22 19:11:21 +03:00
|
|
|
|
{
|
2023-08-23 09:42:53 +03:00
|
|
|
|
YUV_COMBINE_WORK_PARAM current = pool_decode_rect_param(
|
|
|
|
|
®ionRects[y], context, type, pYUVData, iStride, pYUVDstData, iDstStride);
|
2020-10-22 19:11:21 +03:00
|
|
|
|
cb(NULL, ¤t, NULL);
|
|
|
|
|
}
|
|
|
|
|
return TRUE;
|
2017-12-15 13:15:24 +03:00
|
|
|
|
}
|
|
|
|
|
|
2020-10-22 19:11:21 +03:00
|
|
|
|
/* case where we use threads */
|
|
|
|
|
for (waitCount = 0; waitCount < numRegionRects; waitCount++)
|
2017-12-15 13:15:24 +03:00
|
|
|
|
{
|
2024-01-23 18:49:54 +03:00
|
|
|
|
YUV_COMBINE_WORK_PARAM* current = NULL;
|
2022-03-29 14:55:52 +03:00
|
|
|
|
|
|
|
|
|
if (context->work_object_count <= waitCount)
|
|
|
|
|
{
|
2022-10-18 10:51:09 +03:00
|
|
|
|
WLog_ERR(TAG,
|
2023-08-23 09:42:53 +03:00
|
|
|
|
"YUV rect decoder: invalid number of tiles, only support less than %" PRIu32
|
2022-10-18 10:51:09 +03:00
|
|
|
|
", got %" PRIu32,
|
|
|
|
|
context->work_object_count, waitCount);
|
2022-03-29 14:55:52 +03:00
|
|
|
|
goto fail;
|
|
|
|
|
}
|
|
|
|
|
current = &context->work_combined_params[waitCount];
|
2020-10-22 19:11:21 +03:00
|
|
|
|
*current = pool_decode_rect_param(®ionRects[waitCount], context, type, pYUVData, iStride,
|
2023-08-23 09:42:53 +03:00
|
|
|
|
pYUVDstData, iDstStride);
|
2021-03-03 16:06:01 +03:00
|
|
|
|
|
2022-03-29 14:55:52 +03:00
|
|
|
|
if (!submit_object(&context->work_objects[waitCount], cb, current, context))
|
2020-10-22 19:11:21 +03:00
|
|
|
|
goto fail;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rc = TRUE;
|
|
|
|
|
fail:
|
2023-05-22 12:17:02 +03:00
|
|
|
|
free_objects(context->work_objects, context->work_object_count);
|
2020-10-22 19:11:21 +03:00
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-30 00:44:47 +03:00
|
|
|
|
BOOL yuv444_context_decode(YUV_CONTEXT* WINPR_RESTRICT context, BYTE type,
|
|
|
|
|
const BYTE* WINPR_RESTRICT pYUVData[3], const UINT32 iStride[3],
|
|
|
|
|
UINT32 srcYuvHeight, BYTE* WINPR_RESTRICT pYUVDstData[3],
|
|
|
|
|
const UINT32 iDstStride[3], DWORD DstFormat, BYTE* WINPR_RESTRICT dest,
|
|
|
|
|
UINT32 nDstStep, const RECTANGLE_16* WINPR_RESTRICT regionRects,
|
|
|
|
|
UINT32 numRegionRects)
|
2020-10-22 19:11:21 +03:00
|
|
|
|
{
|
|
|
|
|
const BYTE* pYUVCDstData[3];
|
|
|
|
|
|
2022-03-29 14:55:52 +03:00
|
|
|
|
WINPR_ASSERT(context);
|
|
|
|
|
WINPR_ASSERT(pYUVData);
|
|
|
|
|
WINPR_ASSERT(iStride);
|
|
|
|
|
WINPR_ASSERT(pYUVDstData);
|
|
|
|
|
WINPR_ASSERT(iDstStride);
|
|
|
|
|
WINPR_ASSERT(dest);
|
|
|
|
|
WINPR_ASSERT(regionRects || (numRegionRects == 0));
|
|
|
|
|
|
|
|
|
|
if (context->encoder)
|
|
|
|
|
{
|
|
|
|
|
WLog_ERR(TAG, "YUV context set up for encoding, can not decode with it, aborting");
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
2023-08-23 09:42:53 +03:00
|
|
|
|
if (!pool_decode_rect(context, type, pYUVData, iStride, pYUVDstData, iDstStride, regionRects,
|
|
|
|
|
numRegionRects))
|
2017-12-15 13:15:24 +03:00
|
|
|
|
return FALSE;
|
2021-03-12 18:54:45 +03:00
|
|
|
|
|
2020-10-22 19:11:21 +03:00
|
|
|
|
pYUVCDstData[0] = pYUVDstData[0];
|
|
|
|
|
pYUVCDstData[1] = pYUVDstData[1];
|
|
|
|
|
pYUVCDstData[2] = pYUVDstData[2];
|
2023-08-23 09:42:53 +03:00
|
|
|
|
return pool_decode(context, yuv444_process_work_callback, pYUVCDstData, iDstStride,
|
|
|
|
|
srcYuvHeight, DstFormat, dest, nDstStep, regionRects, numRegionRects);
|
2020-10-22 19:11:21 +03:00
|
|
|
|
}
|
|
|
|
|
|
2024-05-30 00:44:47 +03:00
|
|
|
|
BOOL yuv420_context_decode(YUV_CONTEXT* WINPR_RESTRICT context,
|
|
|
|
|
const BYTE* WINPR_RESTRICT pYUVData[3], const UINT32 iStride[3],
|
|
|
|
|
UINT32 yuvHeight, DWORD DstFormat, BYTE* WINPR_RESTRICT dest,
|
|
|
|
|
UINT32 nDstStep, const RECTANGLE_16* WINPR_RESTRICT regionRects,
|
|
|
|
|
UINT32 numRegionRects)
|
2020-10-22 19:11:21 +03:00
|
|
|
|
{
|
2021-10-20 18:56:41 +03:00
|
|
|
|
return pool_decode(context, yuv420_process_work_callback, pYUVData, iStride, yuvHeight,
|
|
|
|
|
DstFormat, dest, nDstStep, regionRects, numRegionRects);
|
2020-10-22 19:11:21 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void CALLBACK yuv420_encode_work_callback(PTP_CALLBACK_INSTANCE instance, void* context,
|
|
|
|
|
PTP_WORK work)
|
|
|
|
|
{
|
|
|
|
|
prim_size_t roi;
|
|
|
|
|
YUV_ENCODE_WORK_PARAM* param = (YUV_ENCODE_WORK_PARAM*)context;
|
|
|
|
|
primitives_t* prims = primitives_get();
|
|
|
|
|
BYTE* pYUVData[3];
|
2024-01-23 18:49:54 +03:00
|
|
|
|
const BYTE* src = NULL;
|
2020-10-22 19:11:21 +03:00
|
|
|
|
|
|
|
|
|
WINPR_UNUSED(instance);
|
|
|
|
|
WINPR_UNUSED(work);
|
2022-03-29 14:55:52 +03:00
|
|
|
|
WINPR_ASSERT(param);
|
2020-10-22 19:11:21 +03:00
|
|
|
|
|
|
|
|
|
roi.width = param->rect.right - param->rect.left;
|
|
|
|
|
roi.height = param->rect.bottom - param->rect.top;
|
|
|
|
|
src = param->pSrcData + param->nSrcStep * param->rect.top +
|
2022-04-28 06:43:31 +03:00
|
|
|
|
param->rect.left * FreeRDPGetBytesPerPixel(param->SrcFormat);
|
2020-10-22 19:11:21 +03:00
|
|
|
|
pYUVData[0] = param->pYUVLumaData[0] + param->rect.top * param->iStride[0] + param->rect.left;
|
|
|
|
|
pYUVData[1] =
|
|
|
|
|
param->pYUVLumaData[1] + param->rect.top / 2 * param->iStride[1] + param->rect.left / 2;
|
|
|
|
|
pYUVData[2] =
|
|
|
|
|
param->pYUVLumaData[2] + param->rect.top / 2 * param->iStride[2] + param->rect.left / 2;
|
|
|
|
|
|
|
|
|
|
if (prims->RGBToYUV420_8u_P3AC4R(src, param->SrcFormat, param->nSrcStep, pYUVData,
|
|
|
|
|
param->iStride, &roi) != PRIMITIVES_SUCCESS)
|
|
|
|
|
{
|
|
|
|
|
WLog_ERR(TAG, "error when decoding lines");
|
2017-12-15 13:15:24 +03:00
|
|
|
|
}
|
2020-10-22 19:11:21 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void CALLBACK yuv444v1_encode_work_callback(PTP_CALLBACK_INSTANCE instance, void* context,
|
|
|
|
|
PTP_WORK work)
|
|
|
|
|
{
|
|
|
|
|
prim_size_t roi;
|
|
|
|
|
YUV_ENCODE_WORK_PARAM* param = (YUV_ENCODE_WORK_PARAM*)context;
|
|
|
|
|
primitives_t* prims = primitives_get();
|
|
|
|
|
BYTE* pYUVLumaData[3];
|
|
|
|
|
BYTE* pYUVChromaData[3];
|
2024-01-23 18:49:54 +03:00
|
|
|
|
const BYTE* src = NULL;
|
2017-12-15 13:15:24 +03:00
|
|
|
|
|
2020-10-22 19:11:21 +03:00
|
|
|
|
WINPR_UNUSED(instance);
|
|
|
|
|
WINPR_UNUSED(work);
|
2022-03-29 14:55:52 +03:00
|
|
|
|
WINPR_ASSERT(param);
|
2020-10-22 19:11:21 +03:00
|
|
|
|
|
|
|
|
|
roi.width = param->rect.right - param->rect.left;
|
|
|
|
|
roi.height = param->rect.bottom - param->rect.top;
|
|
|
|
|
src = param->pSrcData + param->nSrcStep * param->rect.top +
|
2022-04-28 06:43:31 +03:00
|
|
|
|
param->rect.left * FreeRDPGetBytesPerPixel(param->SrcFormat);
|
2020-10-22 19:11:21 +03:00
|
|
|
|
pYUVLumaData[0] =
|
|
|
|
|
param->pYUVLumaData[0] + param->rect.top * param->iStride[0] + param->rect.left;
|
|
|
|
|
pYUVLumaData[1] =
|
|
|
|
|
param->pYUVLumaData[1] + param->rect.top / 2 * param->iStride[1] + param->rect.left / 2;
|
|
|
|
|
pYUVLumaData[2] =
|
|
|
|
|
param->pYUVLumaData[2] + param->rect.top / 2 * param->iStride[2] + param->rect.left / 2;
|
|
|
|
|
pYUVChromaData[0] =
|
|
|
|
|
param->pYUVChromaData[0] + param->rect.top * param->iStride[0] + param->rect.left;
|
|
|
|
|
pYUVChromaData[1] =
|
|
|
|
|
param->pYUVChromaData[1] + param->rect.top / 2 * param->iStride[1] + param->rect.left / 2;
|
|
|
|
|
pYUVChromaData[2] =
|
|
|
|
|
param->pYUVChromaData[2] + param->rect.top / 2 * param->iStride[2] + param->rect.left / 2;
|
|
|
|
|
if (prims->RGBToAVC444YUV(src, param->SrcFormat, param->nSrcStep, pYUVLumaData, param->iStride,
|
|
|
|
|
pYUVChromaData, param->iStride, &roi) != PRIMITIVES_SUCCESS)
|
2017-12-15 13:15:24 +03:00
|
|
|
|
{
|
2020-10-22 19:11:21 +03:00
|
|
|
|
WLog_ERR(TAG, "error when decoding lines");
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-12-15 13:15:24 +03:00
|
|
|
|
|
2020-10-22 19:11:21 +03:00
|
|
|
|
static void CALLBACK yuv444v2_encode_work_callback(PTP_CALLBACK_INSTANCE instance, void* context,
|
|
|
|
|
PTP_WORK work)
|
|
|
|
|
{
|
|
|
|
|
prim_size_t roi;
|
|
|
|
|
YUV_ENCODE_WORK_PARAM* param = (YUV_ENCODE_WORK_PARAM*)context;
|
|
|
|
|
primitives_t* prims = primitives_get();
|
|
|
|
|
BYTE* pYUVLumaData[3];
|
|
|
|
|
BYTE* pYUVChromaData[3];
|
2024-01-23 18:49:54 +03:00
|
|
|
|
const BYTE* src = NULL;
|
2017-12-15 13:15:24 +03:00
|
|
|
|
|
2020-10-22 19:11:21 +03:00
|
|
|
|
WINPR_UNUSED(instance);
|
|
|
|
|
WINPR_UNUSED(work);
|
2022-03-29 14:55:52 +03:00
|
|
|
|
WINPR_ASSERT(param);
|
2017-12-15 13:15:24 +03:00
|
|
|
|
|
2020-10-22 19:11:21 +03:00
|
|
|
|
roi.width = param->rect.right - param->rect.left;
|
|
|
|
|
roi.height = param->rect.bottom - param->rect.top;
|
|
|
|
|
src = param->pSrcData + param->nSrcStep * param->rect.top +
|
2022-04-28 06:43:31 +03:00
|
|
|
|
param->rect.left * FreeRDPGetBytesPerPixel(param->SrcFormat);
|
2020-10-22 19:11:21 +03:00
|
|
|
|
pYUVLumaData[0] =
|
|
|
|
|
param->pYUVLumaData[0] + param->rect.top * param->iStride[0] + param->rect.left;
|
|
|
|
|
pYUVLumaData[1] =
|
|
|
|
|
param->pYUVLumaData[1] + param->rect.top / 2 * param->iStride[1] + param->rect.left / 2;
|
|
|
|
|
pYUVLumaData[2] =
|
|
|
|
|
param->pYUVLumaData[2] + param->rect.top / 2 * param->iStride[2] + param->rect.left / 2;
|
|
|
|
|
pYUVChromaData[0] =
|
|
|
|
|
param->pYUVChromaData[0] + param->rect.top * param->iStride[0] + param->rect.left;
|
|
|
|
|
pYUVChromaData[1] =
|
|
|
|
|
param->pYUVChromaData[1] + param->rect.top / 2 * param->iStride[1] + param->rect.left / 2;
|
|
|
|
|
pYUVChromaData[2] =
|
|
|
|
|
param->pYUVChromaData[2] + param->rect.top / 2 * param->iStride[2] + param->rect.left / 2;
|
|
|
|
|
if (prims->RGBToAVC444YUVv2(src, param->SrcFormat, param->nSrcStep, pYUVLumaData,
|
|
|
|
|
param->iStride, pYUVChromaData, param->iStride,
|
|
|
|
|
&roi) != PRIMITIVES_SUCCESS)
|
|
|
|
|
{
|
|
|
|
|
WLog_ERR(TAG, "error when decoding lines");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-30 00:44:47 +03:00
|
|
|
|
static INLINE YUV_ENCODE_WORK_PARAM pool_encode_fill(
|
|
|
|
|
const RECTANGLE_16* WINPR_RESTRICT rect, YUV_CONTEXT* WINPR_RESTRICT context,
|
|
|
|
|
const BYTE* WINPR_RESTRICT pSrcData, UINT32 nSrcStep, UINT32 SrcFormat, const UINT32 iStride[],
|
|
|
|
|
BYTE* WINPR_RESTRICT pYUVLumaData[], BYTE* WINPR_RESTRICT pYUVChromaData[])
|
2020-10-22 19:11:21 +03:00
|
|
|
|
{
|
|
|
|
|
YUV_ENCODE_WORK_PARAM current = { 0 };
|
|
|
|
|
|
2022-03-29 14:55:52 +03:00
|
|
|
|
WINPR_ASSERT(rect);
|
|
|
|
|
WINPR_ASSERT(context);
|
|
|
|
|
WINPR_ASSERT(pSrcData);
|
|
|
|
|
WINPR_ASSERT(iStride);
|
|
|
|
|
WINPR_ASSERT(pYUVLumaData);
|
|
|
|
|
|
2020-10-22 19:11:21 +03:00
|
|
|
|
current.context = context;
|
|
|
|
|
current.pSrcData = pSrcData;
|
|
|
|
|
current.SrcFormat = SrcFormat;
|
|
|
|
|
current.nSrcStep = nSrcStep;
|
|
|
|
|
current.pYUVLumaData[0] = pYUVLumaData[0];
|
|
|
|
|
current.pYUVLumaData[1] = pYUVLumaData[1];
|
|
|
|
|
current.pYUVLumaData[2] = pYUVLumaData[2];
|
|
|
|
|
if (pYUVChromaData)
|
|
|
|
|
{
|
|
|
|
|
current.pYUVChromaData[0] = pYUVChromaData[0];
|
|
|
|
|
current.pYUVChromaData[1] = pYUVChromaData[1];
|
|
|
|
|
current.pYUVChromaData[2] = pYUVChromaData[2];
|
|
|
|
|
}
|
|
|
|
|
current.iStride[0] = iStride[0];
|
|
|
|
|
current.iStride[1] = iStride[1];
|
|
|
|
|
current.iStride[2] = iStride[2];
|
|
|
|
|
|
|
|
|
|
current.rect = *rect;
|
|
|
|
|
|
|
|
|
|
return current;
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-30 00:44:47 +03:00
|
|
|
|
static BOOL pool_encode(YUV_CONTEXT* WINPR_RESTRICT context, PTP_WORK_CALLBACK cb,
|
|
|
|
|
const BYTE* WINPR_RESTRICT pSrcData, UINT32 nSrcStep, UINT32 SrcFormat,
|
|
|
|
|
const UINT32 iStride[], BYTE* WINPR_RESTRICT pYUVLumaData[],
|
|
|
|
|
BYTE* WINPR_RESTRICT pYUVChromaData[],
|
|
|
|
|
const RECTANGLE_16* WINPR_RESTRICT regionRects, UINT32 numRegionRects)
|
2020-10-22 19:11:21 +03:00
|
|
|
|
{
|
|
|
|
|
BOOL rc = FALSE;
|
|
|
|
|
primitives_t* prims = primitives_get();
|
|
|
|
|
UINT32 waitCount = 0;
|
|
|
|
|
|
2022-03-29 14:55:52 +03:00
|
|
|
|
WINPR_ASSERT(context);
|
|
|
|
|
WINPR_ASSERT(cb);
|
|
|
|
|
WINPR_ASSERT(pSrcData);
|
|
|
|
|
WINPR_ASSERT(iStride);
|
|
|
|
|
WINPR_ASSERT(regionRects || (numRegionRects == 0));
|
|
|
|
|
|
|
|
|
|
if (!context->encoder)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
WLog_ERR(TAG, "YUV context set up for decoding, can not encode with it, aborting");
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-22 19:11:21 +03:00
|
|
|
|
if (!context->useThreads || (primitives_flags(prims) & PRIM_FLAGS_HAVE_EXTGPU))
|
|
|
|
|
{
|
2024-01-30 12:25:38 +03:00
|
|
|
|
for (UINT32 x = 0; x < numRegionRects; x++)
|
2017-12-15 13:15:24 +03:00
|
|
|
|
{
|
2020-10-22 19:11:21 +03:00
|
|
|
|
YUV_ENCODE_WORK_PARAM current =
|
|
|
|
|
pool_encode_fill(®ionRects[x], context, pSrcData, nSrcStep, SrcFormat, iStride,
|
|
|
|
|
pYUVLumaData, pYUVChromaData);
|
|
|
|
|
cb(NULL, ¤t, NULL);
|
2017-12-15 13:15:24 +03:00
|
|
|
|
}
|
2020-10-22 19:11:21 +03:00
|
|
|
|
return TRUE;
|
2017-12-15 13:15:24 +03:00
|
|
|
|
}
|
|
|
|
|
|
2020-10-22 19:11:21 +03:00
|
|
|
|
/* case where we use threads */
|
2024-01-30 12:25:38 +03:00
|
|
|
|
for (UINT32 x = 0; x < numRegionRects; x++)
|
2017-12-15 13:15:24 +03:00
|
|
|
|
{
|
2020-10-22 19:11:21 +03:00
|
|
|
|
const RECTANGLE_16* rect = ®ionRects[x];
|
|
|
|
|
const UINT32 height = rect->bottom - rect->top;
|
|
|
|
|
const UINT32 steps = (height + context->heightStep / 2) / context->heightStep;
|
|
|
|
|
|
2020-11-20 14:37:21 +03:00
|
|
|
|
waitCount += steps;
|
|
|
|
|
}
|
|
|
|
|
|
2024-01-30 12:25:38 +03:00
|
|
|
|
for (UINT32 x = 0; x < numRegionRects; x++)
|
2020-11-20 14:37:21 +03:00
|
|
|
|
{
|
|
|
|
|
const RECTANGLE_16* rect = ®ionRects[x];
|
|
|
|
|
const UINT32 height = rect->bottom - rect->top;
|
|
|
|
|
const UINT32 steps = (height + context->heightStep / 2) / context->heightStep;
|
2020-10-22 19:11:21 +03:00
|
|
|
|
|
2024-01-30 12:25:38 +03:00
|
|
|
|
for (UINT32 y = 0; y < steps; y++)
|
2020-10-22 19:11:21 +03:00
|
|
|
|
{
|
|
|
|
|
RECTANGLE_16 r = *rect;
|
2024-01-23 18:49:54 +03:00
|
|
|
|
YUV_ENCODE_WORK_PARAM* current = NULL;
|
2022-03-29 14:55:52 +03:00
|
|
|
|
|
|
|
|
|
if (context->work_object_count <= waitCount)
|
|
|
|
|
{
|
2022-10-18 10:51:09 +03:00
|
|
|
|
WLog_ERR(TAG,
|
2023-08-23 09:42:53 +03:00
|
|
|
|
"YUV encoder: invalid number of tiles, only support less than %" PRIu32
|
2022-10-18 10:51:09 +03:00
|
|
|
|
", got %" PRIu32,
|
|
|
|
|
context->work_object_count, waitCount);
|
2022-03-29 14:55:52 +03:00
|
|
|
|
goto fail;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
current = &context->work_enc_params[waitCount];
|
2020-10-22 19:11:21 +03:00
|
|
|
|
r.top += y * context->heightStep;
|
|
|
|
|
*current = pool_encode_fill(&r, context, pSrcData, nSrcStep, SrcFormat, iStride,
|
|
|
|
|
pYUVLumaData, pYUVChromaData);
|
2022-03-29 14:55:52 +03:00
|
|
|
|
if (!submit_object(&context->work_objects[waitCount], cb, current, context))
|
2020-10-22 19:11:21 +03:00
|
|
|
|
goto fail;
|
|
|
|
|
waitCount++;
|
|
|
|
|
}
|
2017-12-15 13:15:24 +03:00
|
|
|
|
}
|
|
|
|
|
|
2020-10-22 19:11:21 +03:00
|
|
|
|
rc = TRUE;
|
|
|
|
|
fail:
|
2023-05-22 12:17:02 +03:00
|
|
|
|
free_objects(context->work_objects, context->work_object_count);
|
2020-10-22 19:11:21 +03:00
|
|
|
|
return rc;
|
|
|
|
|
}
|
2017-12-15 13:15:24 +03:00
|
|
|
|
|
2024-05-30 00:44:47 +03:00
|
|
|
|
BOOL yuv420_context_encode(YUV_CONTEXT* WINPR_RESTRICT context, const BYTE* WINPR_RESTRICT pSrcData,
|
|
|
|
|
UINT32 nSrcStep, UINT32 SrcFormat, const UINT32 iStride[3],
|
|
|
|
|
BYTE* WINPR_RESTRICT pYUVData[3],
|
|
|
|
|
const RECTANGLE_16* WINPR_RESTRICT regionRects, UINT32 numRegionRects)
|
2020-10-22 19:11:21 +03:00
|
|
|
|
{
|
|
|
|
|
if (!context || !pSrcData || !iStride || !pYUVData || !regionRects)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
return pool_encode(context, yuv420_encode_work_callback, pSrcData, nSrcStep, SrcFormat, iStride,
|
|
|
|
|
pYUVData, NULL, regionRects, numRegionRects);
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-30 00:44:47 +03:00
|
|
|
|
BOOL yuv444_context_encode(YUV_CONTEXT* WINPR_RESTRICT context, BYTE version,
|
|
|
|
|
const BYTE* WINPR_RESTRICT pSrcData, UINT32 nSrcStep, UINT32 SrcFormat,
|
|
|
|
|
const UINT32 iStride[3], BYTE* WINPR_RESTRICT pYUVLumaData[3],
|
|
|
|
|
BYTE* WINPR_RESTRICT pYUVChromaData[3],
|
|
|
|
|
const RECTANGLE_16* WINPR_RESTRICT regionRects, UINT32 numRegionRects)
|
2020-10-22 19:11:21 +03:00
|
|
|
|
{
|
2024-01-23 18:49:54 +03:00
|
|
|
|
PTP_WORK_CALLBACK cb = NULL;
|
2020-10-22 19:11:21 +03:00
|
|
|
|
switch (version)
|
|
|
|
|
{
|
|
|
|
|
case 1:
|
|
|
|
|
cb = yuv444v1_encode_work_callback;
|
|
|
|
|
break;
|
|
|
|
|
case 2:
|
|
|
|
|
cb = yuv444v2_encode_work_callback;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return pool_encode(context, cb, pSrcData, nSrcStep, SrcFormat, iStride, pYUVLumaData,
|
|
|
|
|
pYUVChromaData, regionRects, numRegionRects);
|
2017-12-15 13:15:24 +03:00
|
|
|
|
}
|