|
Packit |
1fb8d4 |
#include <winpr/sysinfo.h>
|
|
Packit |
1fb8d4 |
#include <winpr/pool.h>
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
#include <freerdp/primitives.h>
|
|
Packit |
1fb8d4 |
#include <freerdp/log.h>
|
|
Packit |
1fb8d4 |
#include <freerdp/codec/yuv.h>
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
#define TAG FREERDP_TAG("codec")
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
struct _YUV_CONTEXT
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
UINT32 width, height;
|
|
Packit |
1fb8d4 |
BOOL useThreads;
|
|
Packit |
1fb8d4 |
UINT32 nthreads;
|
|
Packit |
1fb8d4 |
UINT32 heightStep;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
PTP_POOL threadPool;
|
|
Packit |
1fb8d4 |
TP_CALLBACK_ENVIRON ThreadPoolEnv;
|
|
Packit |
1fb8d4 |
};
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
struct _YUV_PROCESS_WORK_PARAM
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
YUV_CONTEXT* context;
|
|
Packit |
1fb8d4 |
const BYTE* pYUVData[3];
|
|
Packit |
1fb8d4 |
UINT32 iStride[3];
|
|
Packit |
1fb8d4 |
DWORD DstFormat;
|
|
Packit |
1fb8d4 |
BYTE *dest;
|
|
Packit |
1fb8d4 |
UINT32 nDstStep;
|
|
Packit |
1fb8d4 |
UINT32 y;
|
|
Packit |
1fb8d4 |
UINT32 height;
|
|
Packit |
1fb8d4 |
};
|
|
Packit |
1fb8d4 |
typedef struct _YUV_PROCESS_WORK_PARAM YUV_PROCESS_WORK_PARAM;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
static void CALLBACK yuv_process_work_callback(PTP_CALLBACK_INSTANCE instance, void* context,
|
|
Packit |
1fb8d4 |
PTP_WORK work)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
prim_size_t roi;
|
|
Packit |
1fb8d4 |
YUV_PROCESS_WORK_PARAM* param = (YUV_PROCESS_WORK_PARAM*)context;
|
|
Packit |
1fb8d4 |
primitives_t* prims = primitives_get();
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
roi.width = param->context->width;
|
|
Packit |
1fb8d4 |
roi.height = param->height;
|
|
Packit |
1fb8d4 |
if( prims->YUV420ToRGB_8u_P3AC4R(param->pYUVData, param->iStride, param->dest, param->nDstStep,
|
|
Packit |
1fb8d4 |
param->DstFormat, &roi) != PRIMITIVES_SUCCESS)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
WLog_ERR(TAG, "error when decoding lines");
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
void yuv_context_reset(YUV_CONTEXT* context, UINT32 width, UINT32 height)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
context->width = width;
|
|
Packit |
1fb8d4 |
context->height = height;
|
|
Packit |
1fb8d4 |
context->heightStep = (height / context->nthreads);
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
YUV_CONTEXT* yuv_context_new(BOOL encoder)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
SYSTEM_INFO sysInfos;
|
|
Packit |
1fb8d4 |
YUV_CONTEXT* ret = calloc(1, sizeof(*ret));
|
|
Packit |
1fb8d4 |
if (!ret)
|
|
Packit |
1fb8d4 |
return NULL;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
/** do it here to avoid a race condition between threads */
|
|
Packit |
1fb8d4 |
primitives_get();
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
GetNativeSystemInfo(&sysInfos);
|
|
Packit |
1fb8d4 |
ret->useThreads = (sysInfos.dwNumberOfProcessors > 1);
|
|
Packit |
1fb8d4 |
if (ret->useThreads)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
ret->nthreads = sysInfos.dwNumberOfProcessors;
|
|
Packit |
1fb8d4 |
ret->threadPool = CreateThreadpool(NULL);
|
|
Packit |
1fb8d4 |
if (!ret->threadPool)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
goto error_threadpool;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
InitializeThreadpoolEnvironment(&ret->ThreadPoolEnv);
|
|
Packit |
1fb8d4 |
SetThreadpoolCallbackPool(&ret->ThreadPoolEnv, ret->threadPool);
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
else
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
ret->nthreads = 1;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
return ret;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
error_threadpool:
|
|
Packit |
1fb8d4 |
free(ret);
|
|
Packit |
1fb8d4 |
return NULL;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
void yuv_context_free(YUV_CONTEXT* context)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
if (context->useThreads)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
CloseThreadpool(context->threadPool);
|
|
Packit |
1fb8d4 |
DestroyThreadpoolEnvironment(&context->ThreadPoolEnv);
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
free(context);
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
BOOL yuv_context_decode(YUV_CONTEXT* context, const BYTE* pYUVData[3], UINT32 iStride[3],
|
|
Packit |
1fb8d4 |
DWORD DstFormat, BYTE *dest, UINT32 nDstStep)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
UINT32 y, nobjects, i;
|
|
Packit |
1fb8d4 |
PTP_WORK *work_objects = NULL;
|
|
Packit |
1fb8d4 |
YUV_PROCESS_WORK_PARAM *params;
|
|
Packit |
1fb8d4 |
int waitCount = 0;
|
|
Packit |
1fb8d4 |
BOOL ret = TRUE;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (!context->useThreads)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
primitives_t* prims = primitives_get();
|
|
Packit |
1fb8d4 |
prim_size_t roi;
|
|
Packit |
1fb8d4 |
roi.width = context->width;
|
|
Packit |
1fb8d4 |
roi.height = context->height;
|
|
Packit |
1fb8d4 |
return prims->YUV420ToRGB_8u_P3AC4R(pYUVData, iStride, dest, nDstStep,
|
|
Packit |
1fb8d4 |
DstFormat, &roi) == PRIMITIVES_SUCCESS;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
/* case where we use threads */
|
|
Packit |
1fb8d4 |
nobjects = (context->height + context->heightStep - 1) / context->heightStep;
|
|
Packit |
1fb8d4 |
work_objects = (PTP_WORK *)calloc(nobjects, sizeof(PTP_WORK));
|
|
Packit |
1fb8d4 |
if (!work_objects)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
return FALSE;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
params = (YUV_PROCESS_WORK_PARAM *)calloc(nobjects, sizeof(*params));
|
|
Packit |
1fb8d4 |
if (!params)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
free(work_objects);
|
|
Packit |
1fb8d4 |
return FALSE;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
for (i = 0, y = 0; i < nobjects; i++, y += context->heightStep, waitCount++)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
params[i].context = context;
|
|
Packit |
1fb8d4 |
params[i].DstFormat = DstFormat;
|
|
Packit |
1fb8d4 |
params[i].pYUVData[0] = pYUVData[0] + (y * iStride[0]);
|
|
Packit |
1fb8d4 |
params[i].pYUVData[1] = pYUVData[1] + ((y / 2) * iStride[1]);
|
|
Packit |
1fb8d4 |
params[i].pYUVData[2] = pYUVData[2] + ((y / 2) * iStride[2]);
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
params[i].iStride[0] = iStride[0];
|
|
Packit |
1fb8d4 |
params[i].iStride[1] = iStride[1];
|
|
Packit |
1fb8d4 |
params[i].iStride[2] = iStride[2];
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
params[i].nDstStep = nDstStep;
|
|
Packit |
1fb8d4 |
params[i].dest = dest + (nDstStep * y);
|
|
Packit |
1fb8d4 |
params[i].y = y;
|
|
Packit |
1fb8d4 |
if (y + context->heightStep <= context->height)
|
|
Packit |
1fb8d4 |
params[i].height = context->heightStep;
|
|
Packit |
1fb8d4 |
else
|
|
Packit |
1fb8d4 |
params[i].height = context->height % context->heightStep;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
work_objects[i] = CreateThreadpoolWork(yuv_process_work_callback,
|
|
Packit |
1fb8d4 |
(void*) ¶ms[i], &context->ThreadPoolEnv);
|
|
Packit |
1fb8d4 |
if (!work_objects[i])
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
ret = FALSE;
|
|
Packit |
1fb8d4 |
break;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
SubmitThreadpoolWork(work_objects[i]);
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
for (i = 0; i < waitCount; i++)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
WaitForThreadpoolWorkCallbacks(work_objects[i], FALSE);
|
|
Packit |
1fb8d4 |
CloseThreadpoolWork(work_objects[i]);
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
free(work_objects);
|
|
Packit |
1fb8d4 |
free(params);
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
return ret;
|
|
Packit |
1fb8d4 |
}
|