Blame libfreerdp/codec/yuv.c

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