Blame libfreerdp/codec/yuv.c

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*) &params[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
}