Blame libfreerdp/codec/h264.c

Packit Service fa4841
/**
Packit Service fa4841
 * FreeRDP: A Remote Desktop Protocol Implementation
Packit Service fa4841
 * H.264 Bitmap Compression
Packit Service fa4841
 *
Packit Service fa4841
 * Copyright 2014 Mike McDonald <Mike.McDonald@software.dell.com>
Packit Service fa4841
 * Copyright 2017 David Fort <contact@hardening-consulting.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/print.h>
Packit Service fa4841
#include <winpr/library.h>
Packit Service fa4841
#include <winpr/bitstream.h>
Packit Service fa4841
#include <winpr/synch.h>
Packit Service fa4841
Packit Service fa4841
#include <freerdp/primitives.h>
Packit Service fa4841
#include <freerdp/codec/h264.h>
Packit Service fa4841
#include <freerdp/log.h>
Packit Service fa4841
Packit Service fa4841
#include "h264.h"
Packit Service fa4841
Packit Service fa4841
#define TAG FREERDP_TAG("codec")
Packit Service fa4841
Packit Service fa4841
static BOOL avc444_ensure_buffer(H264_CONTEXT* h264, DWORD nDstHeight);
Packit Service fa4841
Packit Service fa4841
BOOL avc420_ensure_buffer(H264_CONTEXT* h264, UINT32 stride, UINT32 width, UINT32 height)
Packit Service fa4841
{
Packit Service fa4841
	if (!h264)
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	if (stride == 0)
Packit Service fa4841
		stride = width;
Packit Service fa4841
Packit Service fa4841
	if (stride % 16 != 0)
Packit Service fa4841
		stride += 16 - stride % 16;
Packit Service fa4841
Packit Service fa4841
	if (height % 16 != 0)
Packit Service fa4841
		height += 16 - height % 16;
Packit Service fa4841
Packit Service b1ea74
	if (!h264->pYUVData[0] || !h264->pYUVData[1] || !h264->pYUVData[2] || (width != h264->width) ||
Packit Service b1ea74
	    (height != h264->height) || (stride != h264->iStride[0]))
Packit Service fa4841
	{
Packit Service fa4841
		h264->iStride[0] = stride;
Packit Service fa4841
		h264->iStride[1] = (stride + 1) / 2;
Packit Service fa4841
		h264->iStride[2] = (stride + 1) / 2;
Packit Service fa4841
		h264->width = width;
Packit Service fa4841
		h264->height = height;
Packit Service fa4841
		_aligned_free(h264->pYUVData[0]);
Packit Service fa4841
		_aligned_free(h264->pYUVData[1]);
Packit Service fa4841
		_aligned_free(h264->pYUVData[2]);
Packit Service fa4841
		h264->pYUVData[0] = _aligned_malloc(h264->iStride[0] * height, 16);
Packit Service fa4841
		h264->pYUVData[1] = _aligned_malloc(h264->iStride[1] * height, 16);
Packit Service fa4841
		h264->pYUVData[2] = _aligned_malloc(h264->iStride[2] * height, 16);
Packit Service fa4841
Packit Service fa4841
		if (!h264->pYUVData[0] || !h264->pYUVData[1] || !h264->pYUVData[2])
Packit Service fa4841
			return FALSE;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	return TRUE;
Packit Service fa4841
}
Packit Service fa4841
Packit Service b1ea74
static BOOL check_rect(const H264_CONTEXT* h264, const RECTANGLE_16* rect, UINT32 nDstWidth,
Packit Service b1ea74
                       UINT32 nDstHeight)
Packit Service fa4841
{
Packit Service fa4841
	/* Check, if the output rectangle is valid in decoded h264 frame. */
Packit Service fa4841
	if ((rect->right > h264->width) || (rect->left > h264->width))
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	if ((rect->top > h264->height) || (rect->bottom > h264->height))
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	/* Check, if the output rectangle is valid in destination buffer. */
Packit Service fa4841
	if ((rect->right > nDstWidth) || (rect->left > nDstWidth))
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	if ((rect->bottom > nDstHeight) || (rect->top > nDstHeight))
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	return TRUE;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static BOOL avc_yuv_to_rgb(H264_CONTEXT* h264, const RECTANGLE_16* regionRects,
Packit Service b1ea74
                           UINT32 numRegionRects, UINT32 nDstWidth, UINT32 nDstHeight,
Packit Service b1ea74
                           UINT32 nDstStep, BYTE* pDstData, DWORD DstFormat, BOOL use444)
Packit Service fa4841
{
Packit Service fa4841
	UINT32 x;
Packit Service fa4841
	BYTE* pDstPoint;
Packit Service fa4841
	prim_size_t roi;
Packit Service fa4841
	INT32 width, height;
Packit Service fa4841
	const BYTE* pYUVPoint[3];
Packit Service fa4841
	primitives_t* prims = primitives_get();
Packit Service fa4841
Packit Service fa4841
	for (x = 0; x < numRegionRects; x++)
Packit Service fa4841
	{
Packit Service fa4841
		const RECTANGLE_16* rect = &(regionRects[x]);
Packit Service fa4841
		const UINT32* iStride;
Packit Service fa4841
		BYTE** ppYUVData;
Packit Service fa4841
Packit Service fa4841
		if (use444)
Packit Service fa4841
		{
Packit Service fa4841
			iStride = h264->iYUV444Stride;
Packit Service fa4841
			ppYUVData = h264->pYUV444Data;
Packit Service fa4841
		}
Packit Service fa4841
		else
Packit Service fa4841
		{
Packit Service fa4841
			iStride = h264->iStride;
Packit Service fa4841
			ppYUVData = h264->pYUVData;
Packit Service fa4841
		}
Packit Service fa4841
Packit Service fa4841
		if (!check_rect(h264, rect, nDstWidth, nDstHeight))
Packit Service fa4841
			return FALSE;
Packit Service fa4841
Packit Service fa4841
		width = rect->right - rect->left;
Packit Service fa4841
		height = rect->bottom - rect->top;
Packit Service fa4841
		pDstPoint = pDstData + rect->top * nDstStep + rect->left * 4;
Packit Service fa4841
		pYUVPoint[0] = ppYUVData[0] + rect->top * iStride[0] + rect->left;
Packit Service fa4841
		pYUVPoint[1] = ppYUVData[1];
Packit Service fa4841
		pYUVPoint[2] = ppYUVData[2];
Packit Service fa4841
Packit Service fa4841
		if (use444)
Packit Service fa4841
		{
Packit Service fa4841
			pYUVPoint[1] += rect->top * iStride[1] + rect->left;
Packit Service fa4841
			pYUVPoint[2] += rect->top * iStride[2] + rect->left;
Packit Service fa4841
		}
Packit Service fa4841
		else
Packit Service fa4841
		{
Packit Service fa4841
			pYUVPoint[1] += rect->top / 2 * iStride[1] + rect->left / 2;
Packit Service fa4841
			pYUVPoint[2] += rect->top / 2 * iStride[2] + rect->left / 2;
Packit Service fa4841
		}
Packit Service fa4841
Packit Service fa4841
		roi.width = width;
Packit Service fa4841
		roi.height = height;
Packit Service fa4841
Packit Service fa4841
		if (use444)
Packit Service fa4841
		{
Packit Service b1ea74
			if (prims->YUV444ToRGB_8u_P3AC4R(pYUVPoint, iStride, pDstPoint, nDstStep, DstFormat,
Packit Service b1ea74
			                                 &roi) != PRIMITIVES_SUCCESS)
Packit Service fa4841
			{
Packit Service fa4841
				return FALSE;
Packit Service fa4841
			}
Packit Service fa4841
		}
Packit Service fa4841
		else
Packit Service fa4841
		{
Packit Service b1ea74
			if (prims->YUV420ToRGB_8u_P3AC4R(pYUVPoint, iStride, pDstPoint, nDstStep, DstFormat,
Packit Service b1ea74
			                                 &roi) != PRIMITIVES_SUCCESS)
Packit Service fa4841
				return FALSE;
Packit Service fa4841
		}
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	return TRUE;
Packit Service fa4841
}
Packit Service fa4841
Packit Service b1ea74
INT32 avc420_decompress(H264_CONTEXT* h264, const BYTE* pSrcData, UINT32 SrcSize, BYTE* pDstData,
Packit Service b1ea74
                        DWORD DstFormat, UINT32 nDstStep, UINT32 nDstWidth, UINT32 nDstHeight,
Packit Service fa4841
                        RECTANGLE_16* regionRects, UINT32 numRegionRects)
Packit Service fa4841
{
Packit Service fa4841
	int status;
Packit Service fa4841
Packit Service fa4841
	if (!h264)
Packit Service fa4841
		return -1001;
Packit Service fa4841
Packit Service fa4841
	status = h264->subsystem->Decompress(h264, pSrcData, SrcSize);
Packit Service fa4841
Packit Service fa4841
	if (status == 0)
Packit Service fa4841
		return 1;
Packit Service fa4841
Packit Service fa4841
	if (status < 0)
Packit Service fa4841
		return status;
Packit Service fa4841
Packit Service b1ea74
	if (!avc_yuv_to_rgb(h264, regionRects, numRegionRects, nDstWidth, nDstHeight, nDstStep,
Packit Service b1ea74
	                    pDstData, DstFormat, FALSE))
Packit Service fa4841
		return -1002;
Packit Service fa4841
Packit Service fa4841
	return 1;
Packit Service fa4841
}
Packit Service fa4841
Packit Service b1ea74
INT32 avc420_compress(H264_CONTEXT* h264, const BYTE* pSrcData, DWORD SrcFormat, UINT32 nSrcStep,
Packit Service b1ea74
                      UINT32 nSrcWidth, UINT32 nSrcHeight, BYTE** ppDstData, UINT32* pDstSize)
Packit Service fa4841
{
Packit Service fa4841
	prim_size_t roi;
Packit Service fa4841
	primitives_t* prims = primitives_get();
Packit Service fa4841
Packit Service fa4841
	if (!h264)
Packit Service fa4841
		return -1;
Packit Service fa4841
Packit Service fa4841
	if (!h264->subsystem->Compress)
Packit Service fa4841
		return -1;
Packit Service fa4841
Packit Service fa4841
	if (!avc420_ensure_buffer(h264, nSrcStep, nSrcWidth, nSrcHeight))
Packit Service fa4841
		return -1;
Packit Service fa4841
Packit Service fa4841
	roi.width = nSrcWidth;
Packit Service fa4841
	roi.height = nSrcHeight;
Packit Service fa4841
Packit Service fa4841
	if (prims->RGBToYUV420_8u_P3AC4R(pSrcData, SrcFormat, nSrcStep, h264->pYUVData, h264->iStride,
Packit Service fa4841
	                                 &roi) != PRIMITIVES_SUCCESS)
Packit Service fa4841
		return -1;
Packit Service fa4841
Packit Service fa4841
	{
Packit Service b1ea74
		const BYTE* pYUVData[3] = { h264->pYUVData[0], h264->pYUVData[1], h264->pYUVData[2] };
Packit Service fa4841
		return h264->subsystem->Compress(h264, pYUVData, h264->iStride, ppDstData, pDstSize);
Packit Service fa4841
	}
Packit Service fa4841
}
Packit Service fa4841
Packit Service b1ea74
INT32 avc444_compress(H264_CONTEXT* h264, const BYTE* pSrcData, DWORD SrcFormat, UINT32 nSrcStep,
Packit Service b1ea74
                      UINT32 nSrcWidth, UINT32 nSrcHeight, BYTE version, BYTE* op, BYTE** ppDstData,
Packit Service b1ea74
                      UINT32* pDstSize, BYTE** ppAuxDstData, UINT32* pAuxDstSize)
Packit Service fa4841
{
Packit Service fa4841
	prim_size_t roi;
Packit Service fa4841
	primitives_t* prims = primitives_get();
Packit Service fa4841
	BYTE* coded;
Packit Service fa4841
	UINT32 codedSize;
Packit Service fa4841
Packit Service fa4841
	if (!h264)
Packit Service fa4841
		return -1;
Packit Service fa4841
Packit Service fa4841
	if (!h264->subsystem->Compress)
Packit Service fa4841
		return -1;
Packit Service fa4841
Packit Service fa4841
	if (!avc420_ensure_buffer(h264, nSrcStep, nSrcWidth, nSrcHeight))
Packit Service fa4841
		return -1;
Packit Service fa4841
Packit Service fa4841
	if (!avc444_ensure_buffer(h264, nSrcHeight))
Packit Service fa4841
		return -1;
Packit Service fa4841
Packit Service fa4841
	roi.width = nSrcWidth;
Packit Service fa4841
	roi.height = nSrcHeight;
Packit Service fa4841
Packit Service fa4841
	switch (version)
Packit Service fa4841
	{
Packit Service fa4841
		case 1:
Packit Service b1ea74
			if (prims->RGBToAVC444YUV(pSrcData, SrcFormat, nSrcStep, h264->pYUV444Data,
Packit Service b1ea74
			                          h264->iStride, h264->pYUVData, h264->iStride,
Packit Service b1ea74
			                          &roi) != PRIMITIVES_SUCCESS)
Packit Service fa4841
				return -1;
Packit Service fa4841
Packit Service fa4841
			break;
Packit Service fa4841
Packit Service fa4841
		case 2:
Packit Service b1ea74
			if (prims->RGBToAVC444YUVv2(pSrcData, SrcFormat, nSrcStep, h264->pYUV444Data,
Packit Service b1ea74
			                            h264->iStride, h264->pYUVData, h264->iStride,
Packit Service b1ea74
			                            &roi) != PRIMITIVES_SUCCESS)
Packit Service fa4841
				return -1;
Packit Service fa4841
Packit Service fa4841
			break;
Packit Service fa4841
Packit Service fa4841
		default:
Packit Service fa4841
			return -1;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	{
Packit Service b1ea74
		const BYTE* pYUV444Data[3] = { h264->pYUV444Data[0], h264->pYUV444Data[1],
Packit Service b1ea74
			                           h264->pYUV444Data[2] };
Packit Service fa4841
Packit Service fa4841
		if (h264->subsystem->Compress(h264, pYUV444Data, h264->iStride, &coded, &codedSize) < 0)
Packit Service fa4841
			return -1;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	memcpy(h264->lumaData, coded, codedSize);
Packit Service fa4841
	*ppDstData = h264->lumaData;
Packit Service fa4841
	*pDstSize = codedSize;
Packit Service fa4841
	{
Packit Service b1ea74
		const BYTE* pYUVData[3] = { h264->pYUVData[0], h264->pYUVData[1], h264->pYUVData[2] };
Packit Service fa4841
Packit Service fa4841
		if (h264->subsystem->Compress(h264, pYUVData, h264->iStride, &coded, &codedSize) < 0)
Packit Service fa4841
			return -1;
Packit Service fa4841
	}
Packit Service fa4841
	*ppAuxDstData = coded;
Packit Service fa4841
	*pAuxDstSize = codedSize;
Packit Service fa4841
	*op = 0;
Packit Service fa4841
	return 0;
Packit Service fa4841
}
Packit Service fa4841
Packit Service b1ea74
static BOOL avc444_ensure_buffer(H264_CONTEXT* h264, DWORD nDstHeight)
Packit Service fa4841
{
Packit Service fa4841
	UINT32 x;
Packit Service fa4841
	const UINT32* piMainStride = h264->iStride;
Packit Service fa4841
	UINT32* piDstSize = h264->iYUV444Size;
Packit Service fa4841
	UINT32* piDstStride = h264->iYUV444Stride;
Packit Service fa4841
	BYTE** ppYUVDstData = h264->pYUV444Data;
Packit Service b1ea74
	const UINT32 pad = nDstHeight % 16;
Packit Service b1ea74
	UINT32 padDstHeight = nDstHeight; /* Need alignment to 16x16 blocks */
Packit Service b1ea74
Packit Service b1ea74
	if (pad != 0)
Packit Service b1ea74
		padDstHeight += 16 - pad;
Packit Service fa4841
Packit Service b1ea74
	if ((piMainStride[0] != piDstStride[0]) || (piDstSize[0] != piMainStride[0] * padDstHeight))
Packit Service fa4841
	{
Packit Service fa4841
		for (x = 0; x < 3; x++)
Packit Service fa4841
		{
Packit Service fa4841
			piDstStride[x] = piMainStride[0];
Packit Service fa4841
			piDstSize[x] = piDstStride[x] * padDstHeight;
Packit Service fa4841
			_aligned_free(ppYUVDstData[x]);
Packit Service fa4841
			ppYUVDstData[x] = _aligned_malloc(piDstSize[x], 16);
Packit Service fa4841
Packit Service fa4841
			if (!ppYUVDstData[x])
Packit Service fa4841
				goto fail;
Packit Service fa4841
Packit Service fa4841
			memset(ppYUVDstData[x], 0, piDstSize[x]);
Packit Service fa4841
		}
Packit Service fa4841
Packit Service fa4841
		_aligned_free(h264->lumaData);
Packit Service fa4841
		h264->lumaData = _aligned_malloc(piDstSize[0] * 4, 16);
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	for (x = 0; x < 3; x++)
Packit Service fa4841
	{
Packit Service fa4841
		if (!ppYUVDstData[x] || (piDstSize[x] == 0) || (piDstStride[x] == 0))
Packit Service fa4841
		{
Packit Service b1ea74
			WLog_Print(h264->log, WLOG_ERROR,
Packit Service b1ea74
			           "YUV buffer not initialized! check your decoder settings");
Packit Service fa4841
			goto fail;
Packit Service fa4841
		}
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if (!h264->lumaData)
Packit Service fa4841
		goto fail;
Packit Service fa4841
Packit Service fa4841
	return TRUE;
Packit Service fa4841
fail:
Packit Service fa4841
	_aligned_free(ppYUVDstData[0]);
Packit Service fa4841
	_aligned_free(ppYUVDstData[1]);
Packit Service fa4841
	_aligned_free(ppYUVDstData[2]);
Packit Service fa4841
	_aligned_free(h264->lumaData);
Packit Service fa4841
	ppYUVDstData[0] = NULL;
Packit Service fa4841
	ppYUVDstData[1] = NULL;
Packit Service fa4841
	ppYUVDstData[2] = NULL;
Packit Service fa4841
	h264->lumaData = NULL;
Packit Service fa4841
	return FALSE;
Packit Service fa4841
}
Packit Service fa4841
Packit Service b1ea74
static BOOL avc444_process_rects(H264_CONTEXT* h264, const BYTE* pSrcData, UINT32 SrcSize,
Packit Service b1ea74
                                 BYTE* pDstData, UINT32 DstFormat, UINT32 nDstStep,
Packit Service b1ea74
                                 UINT32 nDstWidth, UINT32 nDstHeight, const RECTANGLE_16* rects,
Packit Service b1ea74
                                 UINT32 nrRects, avc444_frame_type type)
Packit Service fa4841
{
Packit Service fa4841
	const primitives_t* prims = primitives_get();
Packit Service fa4841
	UINT32 x;
Packit Service fa4841
	UINT32* piDstStride = h264->iYUV444Stride;
Packit Service fa4841
	BYTE** ppYUVDstData = h264->pYUV444Data;
Packit Service fa4841
	const UINT32* piStride = h264->iStride;
Packit Service b1ea74
	const BYTE* const* ppYUVData = (const BYTE* const*)h264->pYUVData;
Packit Service fa4841
Packit Service fa4841
	if (h264->subsystem->Decompress(h264, pSrcData, SrcSize) < 0)
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	if (!avc444_ensure_buffer(h264, nDstHeight))
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	for (x = 0; x < nrRects; x++)
Packit Service fa4841
	{
Packit Service fa4841
		const RECTANGLE_16* rect = &rects[x];
Packit Service b1ea74
		const UINT32 alignedWidth =
Packit Service b1ea74
		    h264->width + ((h264->width % 16 != 0) ? 16 - h264->width % 16 : 0);
Packit Service b1ea74
		const UINT32 alignedHeight =
Packit Service b1ea74
		    h264->height + ((h264->height % 16 != 0) ? 16 - h264->height % 16 : 0);
Packit Service fa4841
Packit Service fa4841
		if (!check_rect(h264, rect, nDstWidth, nDstHeight))
Packit Service fa4841
			continue;
Packit Service fa4841
Packit Service b1ea74
		if (prims->YUV420CombineToYUV444(type, ppYUVData, piStride, alignedWidth, alignedHeight,
Packit Service b1ea74
		                                 ppYUVDstData, piDstStride, rect) != PRIMITIVES_SUCCESS)
Packit Service fa4841
			return FALSE;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service b1ea74
	if (!avc_yuv_to_rgb(h264, rects, nrRects, nDstWidth, nDstHeight, nDstStep, pDstData, DstFormat,
Packit Service b1ea74
	                    TRUE))
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	return TRUE;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
#if defined(AVC444_FRAME_STAT)
Packit Service fa4841
static UINT64 op1 = 0;
Packit Service fa4841
static double op1sum = 0;
Packit Service fa4841
static UINT64 op2 = 0;
Packit Service fa4841
static double op2sum = 0;
Packit Service fa4841
static UINT64 op3 = 0;
Packit Service fa4841
static double op3sum = 0;
Packit Service fa4841
static double avg(UINT64* count, double old, double size)
Packit Service fa4841
{
Packit Service fa4841
	double tmp = size + *count * old;
Packit Service fa4841
	(*count)++;
Packit Service fa4841
	tmp = tmp / *count;
Packit Service fa4841
	return tmp;
Packit Service fa4841
}
Packit Service fa4841
#endif
Packit Service fa4841
Packit Service b1ea74
INT32 avc444_decompress(H264_CONTEXT* h264, BYTE op, RECTANGLE_16* regionRects,
Packit Service b1ea74
                        UINT32 numRegionRects, const BYTE* pSrcData, UINT32 SrcSize,
Packit Service fa4841
                        RECTANGLE_16* auxRegionRects, UINT32 numAuxRegionRect,
Packit Service b1ea74
                        const BYTE* pAuxSrcData, UINT32 AuxSrcSize, BYTE* pDstData, DWORD DstFormat,
Packit Service b1ea74
                        UINT32 nDstStep, UINT32 nDstWidth, UINT32 nDstHeight, UINT32 codecId)
Packit Service fa4841
{
Packit Service fa4841
	INT32 status = -1;
Packit Service b1ea74
	avc444_frame_type chroma =
Packit Service b1ea74
	    (codecId == RDPGFX_CODECID_AVC444) ? AVC444_CHROMAv1 : AVC444_CHROMAv2;
Packit Service fa4841
Packit Service b1ea74
	if (!h264 || !regionRects || !pSrcData || !pDstData)
Packit Service fa4841
		return -1001;
Packit Service fa4841
Packit Service fa4841
	switch (op)
Packit Service fa4841
	{
Packit Service fa4841
		case 0: /* YUV420 in stream 1
Packit Service b1ea74
		         * Chroma420 in stream 2 */
Packit Service b1ea74
			if (!avc444_process_rects(h264, pSrcData, SrcSize, pDstData, DstFormat, nDstStep,
Packit Service b1ea74
			                          nDstWidth, nDstHeight, regionRects, numRegionRects,
Packit Service b1ea74
			                          AVC444_LUMA))
Packit Service fa4841
				status = -1;
Packit Service b1ea74
			else if (!avc444_process_rects(h264, pAuxSrcData, AuxSrcSize, pDstData, DstFormat,
Packit Service b1ea74
			                               nDstStep, nDstWidth, nDstHeight, auxRegionRects,
Packit Service b1ea74
			                               numAuxRegionRect, chroma))
Packit Service fa4841
				status = -1;
Packit Service fa4841
			else
Packit Service fa4841
				status = 0;
Packit Service fa4841
Packit Service fa4841
			break;
Packit Service fa4841
Packit Service fa4841
		case 2: /* Chroma420 in stream 1 */
Packit Service b1ea74
			if (!avc444_process_rects(h264, pSrcData, SrcSize, pDstData, DstFormat, nDstStep,
Packit Service b1ea74
			                          nDstWidth, nDstHeight, regionRects, numRegionRects, chroma))
Packit Service fa4841
				status = -1;
Packit Service fa4841
			else
Packit Service fa4841
				status = 0;
Packit Service fa4841
Packit Service fa4841
			break;
Packit Service fa4841
Packit Service fa4841
		case 1: /* YUV420 in stream 1 */
Packit Service b1ea74
			if (!avc444_process_rects(h264, pSrcData, SrcSize, pDstData, DstFormat, nDstStep,
Packit Service b1ea74
			                          nDstWidth, nDstHeight, regionRects, numRegionRects,
Packit Service b1ea74
			                          AVC444_LUMA))
Packit Service fa4841
				status = -1;
Packit Service fa4841
			else
Packit Service fa4841
				status = 0;
Packit Service fa4841
Packit Service fa4841
			break;
Packit Service fa4841
Packit Service fa4841
		default: /* WTF? */
Packit Service fa4841
			break;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
#if defined(AVC444_FRAME_STAT)
Packit Service fa4841
Packit Service fa4841
	switch (op)
Packit Service fa4841
	{
Packit Service fa4841
		case 0:
Packit Service fa4841
			op1sum = avg(&op1, op1sum, SrcSize + AuxSrcSize);
Packit Service fa4841
			break;
Packit Service fa4841
Packit Service fa4841
		case 1:
Packit Service fa4841
			op2sum = avg(&op2, op2sum, SrcSize);
Packit Service fa4841
			break;
Packit Service fa4841
Packit Service fa4841
		case 2:
Packit Service fa4841
			op3sum = avg(&op3, op3sum, SrcSize);
Packit Service fa4841
			break;
Packit Service fa4841
Packit Service fa4841
		default:
Packit Service fa4841
			break;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	WLog_Print(h264->log, WLOG_INFO,
Packit Service b1ea74
	           "luma=%" PRIu64 " [avg=%lf] chroma=%" PRIu64 " [avg=%lf] combined=%" PRIu64
Packit Service b1ea74
	           " [avg=%lf]",
Packit Service fa4841
	           op1, op1sum, op2, op2sum, op3, op3sum);
Packit Service fa4841
#endif
Packit Service fa4841
	return status;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
#define MAX_SUBSYSTEMS 10
Packit Service fa4841
static INIT_ONCE subsystems_once = INIT_ONCE_STATIC_INIT;
Packit Service fa4841
static H264_CONTEXT_SUBSYSTEM* subSystems[MAX_SUBSYSTEMS];
Packit Service fa4841
Packit Service fa4841
#if defined(_WIN32) && defined(WITH_MEDIA_FOUNDATION)
Packit Service fa4841
extern H264_CONTEXT_SUBSYSTEM g_Subsystem_MF;
Packit Service fa4841
#endif
Packit Service fa4841
Packit Service fa4841
static BOOL CALLBACK h264_register_subsystems(PINIT_ONCE once, PVOID param, PVOID* context)
Packit Service fa4841
{
Packit Service fa4841
	int i = 0;
Packit Service fa4841
	ZeroMemory(subSystems, sizeof(subSystems));
Packit Service fa4841
#if defined(_WIN32) && defined(WITH_MEDIA_FOUNDATION)
Packit Service fa4841
	{
Packit Service fa4841
		subSystems[i] = &g_Subsystem_MF;
Packit Service fa4841
		i++;
Packit Service fa4841
	}
Packit Service fa4841
#endif
Packit Service fa4841
#ifdef WITH_OPENH264
Packit Service fa4841
	{
Packit Service fa4841
		extern H264_CONTEXT_SUBSYSTEM g_Subsystem_OpenH264;
Packit Service fa4841
		subSystems[i] = &g_Subsystem_OpenH264;
Packit Service fa4841
		i++;
Packit Service fa4841
	}
Packit Service fa4841
#endif
Packit Service fa4841
#ifdef WITH_FFMPEG
Packit Service fa4841
	{
Packit Service fa4841
		extern H264_CONTEXT_SUBSYSTEM g_Subsystem_libavcodec;
Packit Service fa4841
		subSystems[i] = &g_Subsystem_libavcodec;
Packit Service fa4841
		i++;
Packit Service fa4841
	}
Packit Service fa4841
#endif
Packit Service fa4841
#ifdef WITH_X264
Packit Service fa4841
	{
Packit Service fa4841
		extern H264_CONTEXT_SUBSYSTEM g_Subsystem_x264;
Packit Service fa4841
		subSystems[i] = &g_Subsystem_x264;
Packit Service fa4841
		i++;
Packit Service fa4841
	}
Packit Service fa4841
#endif
Packit Service fa4841
	return i > 0;
Packit Service fa4841
}
Packit Service fa4841
Packit Service b1ea74
static BOOL h264_context_init(H264_CONTEXT* h264)
Packit Service fa4841
{
Packit Service fa4841
	int i;
Packit Service fa4841
Packit Service fa4841
	if (!h264)
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	h264->log = WLog_Get(TAG);
Packit Service fa4841
Packit Service fa4841
	if (!h264->log)
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	h264->subsystem = NULL;
Packit Service fa4841
	InitOnceExecuteOnce(&subsystems_once, h264_register_subsystems, NULL, NULL);
Packit Service fa4841
Packit Service fa4841
	for (i = 0; i < MAX_SUBSYSTEMS; i++)
Packit Service fa4841
	{
Packit Service fa4841
		H264_CONTEXT_SUBSYSTEM* subsystem = subSystems[i];
Packit Service fa4841
Packit Service fa4841
		if (!subsystem || !subsystem->Init)
Packit Service fa4841
			break;
Packit Service fa4841
Packit Service fa4841
		if (subsystem->Init(h264))
Packit Service fa4841
		{
Packit Service fa4841
			h264->subsystem = subsystem;
Packit Service fa4841
			return TRUE;
Packit Service fa4841
		}
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	return FALSE;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
BOOL h264_context_reset(H264_CONTEXT* h264, UINT32 width, UINT32 height)
Packit Service fa4841
{
Packit Service fa4841
	if (!h264)
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	h264->width = width;
Packit Service fa4841
	h264->height = height;
Packit Service fa4841
	return TRUE;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
H264_CONTEXT* h264_context_new(BOOL Compressor)
Packit Service fa4841
{
Packit Service fa4841
	H264_CONTEXT* h264;
Packit Service b1ea74
	h264 = (H264_CONTEXT*)calloc(1, sizeof(H264_CONTEXT));
Packit Service fa4841
Packit Service fa4841
	if (h264)
Packit Service fa4841
	{
Packit Service fa4841
		h264->Compressor = Compressor;
Packit Service fa4841
Packit Service fa4841
		if (Compressor)
Packit Service fa4841
		{
Packit Service fa4841
			/* Default compressor settings, may be changed by caller */
Packit Service fa4841
			h264->BitRate = 1000000;
Packit Service fa4841
			h264->FrameRate = 30;
Packit Service fa4841
		}
Packit Service fa4841
Packit Service fa4841
		if (!h264_context_init(h264))
Packit Service fa4841
		{
Packit Service fa4841
			free(h264);
Packit Service fa4841
			return NULL;
Packit Service fa4841
		}
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	return h264;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
void h264_context_free(H264_CONTEXT* h264)
Packit Service fa4841
{
Packit Service fa4841
	if (h264)
Packit Service fa4841
	{
Packit Service fa4841
		h264->subsystem->Uninit(h264);
Packit Service fa4841
		_aligned_free(h264->pYUV444Data[0]);
Packit Service fa4841
		_aligned_free(h264->pYUV444Data[1]);
Packit Service fa4841
		_aligned_free(h264->pYUV444Data[2]);
Packit Service fa4841
		_aligned_free(h264->lumaData);
Packit Service fa4841
		free(h264);
Packit Service fa4841
	}
Packit Service fa4841
}