Blame channels/rdpgfx/client/rdpgfx_codec.c

Packit Service fa4841
/**
Packit Service fa4841
 * FreeRDP: A Remote Desktop Protocol Implementation
Packit Service fa4841
 * Graphics Pipeline Extension
Packit Service fa4841
 *
Packit Service fa4841
 * Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
Packit Service fa4841
 * Copyright 2015 Thincast Technologies GmbH
Packit Service fa4841
 * Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
Packit Service fa4841
 *
Packit Service fa4841
 * Licensed under the Apache License, Version 2.0 (the "License");
Packit Service fa4841
 * you may not use this file except in compliance with the License.
Packit Service fa4841
 * You may obtain a copy of the License at
Packit Service fa4841
 *
Packit Service fa4841
 *     http://www.apache.org/licenses/LICENSE-2.0
Packit Service fa4841
 *
Packit Service fa4841
 * Unless required by applicable law or agreed to in writing, software
Packit Service fa4841
 * distributed under the License is distributed on an "AS IS" BASIS,
Packit Service fa4841
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Packit Service fa4841
 * See the License for the specific language governing permissions and
Packit Service fa4841
 * limitations under the License.
Packit Service fa4841
 */
Packit Service fa4841
Packit Service fa4841
#ifdef HAVE_CONFIG_H
Packit Service fa4841
#include "config.h"
Packit Service fa4841
#endif
Packit Service fa4841
Packit Service fa4841
#include <winpr/crt.h>
Packit Service fa4841
#include <winpr/stream.h>
Packit Service fa4841
#include <freerdp/log.h>
Packit Service fa4841
#include <freerdp/utils/profiler.h>
Packit Service fa4841
Packit Service fa4841
#include "rdpgfx_common.h"
Packit Service fa4841
Packit Service fa4841
#include "rdpgfx_codec.h"
Packit Service fa4841
Packit Service fa4841
#define TAG CHANNELS_TAG("rdpgfx.client")
Packit Service fa4841
Packit Service fa4841
/**
Packit Service fa4841
 * Function description
Packit Service fa4841
 *
Packit Service fa4841
 * @return 0 on success, otherwise a Win32 error code
Packit Service fa4841
 */
Packit Service b1ea74
static UINT rdpgfx_read_h264_metablock(RDPGFX_PLUGIN* gfx, wStream* s, RDPGFX_H264_METABLOCK* meta)
Packit Service fa4841
{
Packit Service fa4841
	UINT32 index;
Packit Service fa4841
	RECTANGLE_16* regionRect;
Packit Service fa4841
	RDPGFX_H264_QUANT_QUALITY* quantQualityVal;
Packit Service fa4841
	UINT error = ERROR_INVALID_DATA;
Packit Service fa4841
	meta->regionRects = NULL;
Packit Service fa4841
	meta->quantQualityVals = NULL;
Packit Service fa4841
Packit Service fa4841
	if (Stream_GetRemainingLength(s) < 4)
Packit Service fa4841
	{
Packit Service fa4841
		WLog_ERR(TAG, "not enough data!");
Packit Service fa4841
		goto error_out;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	Stream_Read_UINT32(s, meta->numRegionRects); /* numRegionRects (4 bytes) */
Packit Service fa4841
Packit Service fa4841
	if (Stream_GetRemainingLength(s) < (meta->numRegionRects * 8))
Packit Service fa4841
	{
Packit Service fa4841
		WLog_ERR(TAG, "not enough data!");
Packit Service fa4841
		goto error_out;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service b1ea74
	meta->regionRects = (RECTANGLE_16*)calloc(meta->numRegionRects, sizeof(RECTANGLE_16));
Packit Service fa4841
Packit Service fa4841
	if (!meta->regionRects)
Packit Service fa4841
	{
Packit Service fa4841
		WLog_ERR(TAG, "malloc failed!");
Packit Service fa4841
		error = CHANNEL_RC_NO_MEMORY;
Packit Service fa4841
		goto error_out;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service b1ea74
	meta->quantQualityVals =
Packit Service b1ea74
	    (RDPGFX_H264_QUANT_QUALITY*)calloc(meta->numRegionRects, sizeof(RDPGFX_H264_QUANT_QUALITY));
Packit Service fa4841
Packit Service fa4841
	if (!meta->quantQualityVals)
Packit Service fa4841
	{
Packit Service fa4841
		WLog_ERR(TAG, "malloc failed!");
Packit Service fa4841
		error = CHANNEL_RC_NO_MEMORY;
Packit Service fa4841
		goto error_out;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service b1ea74
	WLog_DBG(TAG, "H264_METABLOCK: numRegionRects: %" PRIu32 "", meta->numRegionRects);
Packit Service fa4841
Packit Service fa4841
	for (index = 0; index < meta->numRegionRects; index++)
Packit Service fa4841
	{
Packit Service fa4841
		regionRect = &(meta->regionRects[index]);
Packit Service fa4841
Packit Service fa4841
		if ((error = rdpgfx_read_rect16(s, regionRect)))
Packit Service fa4841
		{
Packit Service b1ea74
			WLog_ERR(TAG, "rdpgfx_read_rect16 failed with error %" PRIu32 "!", error);
Packit Service fa4841
			goto error_out;
Packit Service fa4841
		}
Packit Service fa4841
Packit Service fa4841
		WLog_DBG(TAG,
Packit Service b1ea74
		         "regionRects[%" PRIu32 "]: left: %" PRIu16 " top: %" PRIu16 " right: %" PRIu16
Packit Service b1ea74
		         " bottom: %" PRIu16 "",
Packit Service fa4841
		         index, regionRect->left, regionRect->top, regionRect->right, regionRect->bottom);
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if (Stream_GetRemainingLength(s) < (meta->numRegionRects * 2))
Packit Service fa4841
	{
Packit Service fa4841
		WLog_ERR(TAG, "not enough data!");
Packit Service fa4841
		error = ERROR_INVALID_DATA;
Packit Service fa4841
		goto error_out;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	for (index = 0; index < meta->numRegionRects; index++)
Packit Service fa4841
	{
Packit Service fa4841
		quantQualityVal = &(meta->quantQualityVals[index]);
Packit Service b1ea74
		Stream_Read_UINT8(s, quantQualityVal->qpVal);      /* qpVal (1 byte) */
Packit Service fa4841
		Stream_Read_UINT8(s, quantQualityVal->qualityVal); /* qualityVal (1 byte) */
Packit Service fa4841
		quantQualityVal->qp = quantQualityVal->qpVal & 0x3F;
Packit Service fa4841
		quantQualityVal->r = (quantQualityVal->qpVal >> 6) & 1;
Packit Service fa4841
		quantQualityVal->p = (quantQualityVal->qpVal >> 7) & 1;
Packit Service fa4841
		WLog_DBG(TAG,
Packit Service b1ea74
		         "quantQualityVals[%" PRIu32 "]: qp: %" PRIu8 " r: %" PRIu8 " p: %" PRIu8
Packit Service b1ea74
		         " qualityVal: %" PRIu8 "",
Packit Service b1ea74
		         index, quantQualityVal->qp, quantQualityVal->r, quantQualityVal->p,
Packit Service b1ea74
		         quantQualityVal->qualityVal);
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	return CHANNEL_RC_OK;
Packit Service fa4841
error_out:
Packit Service fa4841
	free(meta->regionRects);
Packit Service fa4841
	meta->regionRects = NULL;
Packit Service fa4841
	free(meta->quantQualityVals);
Packit Service fa4841
	meta->quantQualityVals = NULL;
Packit Service fa4841
	return error;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
/**
Packit Service fa4841
 * Function description
Packit Service fa4841
 *
Packit Service fa4841
 * @return 0 on success, otherwise a Win32 error code
Packit Service fa4841
 */
Packit Service fa4841
static UINT rdpgfx_decode_AVC420(RDPGFX_PLUGIN* gfx, RDPGFX_SURFACE_COMMAND* cmd)
Packit Service fa4841
{
Packit Service fa4841
	UINT error;
Packit Service fa4841
	wStream* s;
Packit Service fa4841
	RDPGFX_AVC420_BITMAP_STREAM h264;
Packit Service b1ea74
	RdpgfxClientContext* context = (RdpgfxClientContext*)gfx->iface.pInterface;
Packit Service fa4841
	s = Stream_New(cmd->data, cmd->length);
Packit Service fa4841
Packit Service fa4841
	if (!s)
Packit Service fa4841
	{
Packit Service fa4841
		WLog_ERR(TAG, "Stream_New failed!");
Packit Service fa4841
		return CHANNEL_RC_NO_MEMORY;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if ((error = rdpgfx_read_h264_metablock(gfx, s, &(h264.meta))))
Packit Service fa4841
	{
Packit Service fa4841
		Stream_Free(s, FALSE);
Packit Service b1ea74
		WLog_ERR(TAG, "rdpgfx_read_h264_metablock failed with error %" PRIu32 "!", error);
Packit Service fa4841
		return error;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	h264.data = Stream_Pointer(s);
Packit Service b1ea74
	h264.length = (UINT32)Stream_GetRemainingLength(s);
Packit Service fa4841
	Stream_Free(s, FALSE);
Packit Service b1ea74
	cmd->extra = (void*)&h264;
Packit Service fa4841
Packit Service fa4841
	if (context)
Packit Service fa4841
	{
Packit Service fa4841
		IFCALLRET(context->SurfaceCommand, error, context, cmd);
Packit Service fa4841
Packit Service fa4841
		if (error)
Packit Service b1ea74
			WLog_ERR(TAG, "context->SurfaceCommand failed with error %" PRIu32 "", error);
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	free(h264.meta.regionRects);
Packit Service fa4841
	free(h264.meta.quantQualityVals);
Packit Service fa4841
	return error;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
/**
Packit Service fa4841
 * Function description
Packit Service fa4841
 *
Packit Service fa4841
 * @return 0 on success, otherwise a Win32 error code
Packit Service fa4841
 */
Packit Service fa4841
static UINT rdpgfx_decode_AVC444(RDPGFX_PLUGIN* gfx, RDPGFX_SURFACE_COMMAND* cmd)
Packit Service fa4841
{
Packit Service fa4841
	UINT error;
Packit Service fa4841
	UINT32 tmp;
Packit Service fa4841
	size_t pos1, pos2;
Packit Service fa4841
	wStream* s;
Packit Service fa4841
	RDPGFX_AVC444_BITMAP_STREAM h264 = { 0 };
Packit Service b1ea74
	RdpgfxClientContext* context = (RdpgfxClientContext*)gfx->iface.pInterface;
Packit Service fa4841
	s = Stream_New(cmd->data, cmd->length);
Packit Service fa4841
Packit Service fa4841
	if (!s)
Packit Service fa4841
	{
Packit Service fa4841
		WLog_ERR(TAG, "Stream_New failed!");
Packit Service fa4841
		return CHANNEL_RC_NO_MEMORY;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if (Stream_GetRemainingLength(s) < 4)
Packit Service fa4841
	{
Packit Service fa4841
		error = ERROR_INVALID_DATA;
Packit Service fa4841
		goto fail;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	Stream_Read_UINT32(s, tmp);
Packit Service fa4841
	h264.cbAvc420EncodedBitstream1 = tmp & 0x3FFFFFFFUL;
Packit Service fa4841
	h264.LC = (tmp >> 30UL) & 0x03UL;
Packit Service fa4841
Packit Service fa4841
	if (h264.LC == 0x03)
Packit Service fa4841
	{
Packit Service fa4841
		error = ERROR_INVALID_DATA;
Packit Service fa4841
		goto fail;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	pos1 = Stream_GetPosition(s);
Packit Service fa4841
Packit Service fa4841
	if ((error = rdpgfx_read_h264_metablock(gfx, s, &(h264.bitstream[0].meta))))
Packit Service fa4841
	{
Packit Service b1ea74
		WLog_ERR(TAG, "rdpgfx_read_h264_metablock failed with error %" PRIu32 "!", error);
Packit Service fa4841
		goto fail;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	pos2 = Stream_GetPosition(s);
Packit Service fa4841
	h264.bitstream[0].data = Stream_Pointer(s);
Packit Service fa4841
Packit Service fa4841
	if (h264.LC == 0)
Packit Service fa4841
	{
Packit Service fa4841
		tmp = h264.cbAvc420EncodedBitstream1 - pos2 + pos1;
Packit Service fa4841
Packit Service fa4841
		if (Stream_GetRemainingLength(s) < tmp)
Packit Service fa4841
		{
Packit Service fa4841
			error = ERROR_INVALID_DATA;
Packit Service fa4841
			goto fail;
Packit Service fa4841
		}
Packit Service fa4841
Packit Service fa4841
		h264.bitstream[0].length = tmp;
Packit Service fa4841
		Stream_Seek(s, tmp);
Packit Service fa4841
Packit Service fa4841
		if ((error = rdpgfx_read_h264_metablock(gfx, s, &(h264.bitstream[1].meta))))
Packit Service fa4841
		{
Packit Service b1ea74
			WLog_ERR(TAG, "rdpgfx_read_h264_metablock failed with error %" PRIu32 "!", error);
Packit Service fa4841
			goto fail;
Packit Service fa4841
		}
Packit Service fa4841
Packit Service fa4841
		h264.bitstream[1].data = Stream_Pointer(s);
Packit Service fa4841
		h264.bitstream[1].length = Stream_GetRemainingLength(s);
Packit Service fa4841
	}
Packit Service fa4841
	else
Packit Service fa4841
		h264.bitstream[0].length = Stream_GetRemainingLength(s);
Packit Service fa4841
Packit Service b1ea74
	cmd->extra = (void*)&h264;
Packit Service fa4841
Packit Service fa4841
	if (context)
Packit Service fa4841
	{
Packit Service fa4841
		IFCALLRET(context->SurfaceCommand, error, context, cmd);
Packit Service fa4841
Packit Service fa4841
		if (error)
Packit Service b1ea74
			WLog_ERR(TAG, "context->SurfaceCommand failed with error %" PRIu32 "", error);
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
fail:
Packit Service fa4841
	Stream_Free(s, FALSE);
Packit Service fa4841
	free(h264.bitstream[0].meta.regionRects);
Packit Service fa4841
	free(h264.bitstream[0].meta.quantQualityVals);
Packit Service fa4841
	free(h264.bitstream[1].meta.regionRects);
Packit Service fa4841
	free(h264.bitstream[1].meta.quantQualityVals);
Packit Service fa4841
	return error;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
/**
Packit Service fa4841
 * Function description
Packit Service fa4841
 *
Packit Service fa4841
 * @return 0 on success, otherwise a Win32 error code
Packit Service fa4841
 */
Packit Service fa4841
UINT rdpgfx_decode(RDPGFX_PLUGIN* gfx, RDPGFX_SURFACE_COMMAND* cmd)
Packit Service fa4841
{
Packit Service fa4841
	UINT error = CHANNEL_RC_OK;
Packit Service b1ea74
	RdpgfxClientContext* context = (RdpgfxClientContext*)gfx->iface.pInterface;
Packit Service fa4841
	PROFILER_ENTER(context->SurfaceProfiler)
Packit Service fa4841
Packit Service fa4841
	switch (cmd->codecId)
Packit Service fa4841
	{
Packit Service fa4841
		case RDPGFX_CODECID_AVC420:
Packit Service fa4841
			if ((error = rdpgfx_decode_AVC420(gfx, cmd)))
Packit Service b1ea74
				WLog_ERR(TAG, "rdpgfx_decode_AVC420 failed with error %" PRIu32 "", error);
Packit Service fa4841
Packit Service fa4841
			break;
Packit Service fa4841
Packit Service fa4841
		case RDPGFX_CODECID_AVC444:
Packit Service fa4841
		case RDPGFX_CODECID_AVC444v2:
Packit Service fa4841
			if ((error = rdpgfx_decode_AVC444(gfx, cmd)))
Packit Service b1ea74
				WLog_ERR(TAG, "rdpgfx_decode_AVC444 failed with error %" PRIu32 "", error);
Packit Service fa4841
Packit Service fa4841
			break;
Packit Service fa4841
Packit Service fa4841
		default:
Packit Service fa4841
			if (context)
Packit Service fa4841
			{
Packit Service fa4841
				IFCALLRET(context->SurfaceCommand, error, context, cmd);
Packit Service fa4841
Packit Service fa4841
				if (error)
Packit Service b1ea74
					WLog_ERR(TAG, "context->SurfaceCommand failed with error %" PRIu32 "", error);
Packit Service fa4841
			}
Packit Service fa4841
Packit Service fa4841
			break;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	PROFILER_EXIT(context->SurfaceProfiler)
Packit Service fa4841
	return error;
Packit Service fa4841
}