From f34679397024a67ce6d568aad9ede19a8858b6f3 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Fri, 20 Nov 2020 12:37:21 +0100 Subject: [PATCH] Refactored encoder functions to return changed areas --- channels/rdpgfx/client/rdpgfx_codec.c | 14 +- include/freerdp/codec/h264.h | 25 +- libfreerdp/codec/h264.c | 332 ++++++++++++++++++++----- libfreerdp/codec/yuv.c | 57 +++-- libfreerdp/primitives/prim_YUV_ssse3.c | 5 +- server/shadow/shadow_client.c | 87 ++++--- winpr/libwinpr/crt/alignment.c | 29 ++- 7 files changed, 392 insertions(+), 157 deletions(-) diff --git a/channels/rdpgfx/client/rdpgfx_codec.c b/channels/rdpgfx/client/rdpgfx_codec.c index d89278c75..6f825d47a 100644 --- a/channels/rdpgfx/client/rdpgfx_codec.c +++ b/channels/rdpgfx/client/rdpgfx_codec.c @@ -123,10 +123,7 @@ static UINT rdpgfx_read_h264_metablock(RDPGFX_PLUGIN* gfx, wStream* s, RDPGFX_H2 return CHANNEL_RC_OK; error_out: - free(meta->regionRects); - meta->regionRects = NULL; - free(meta->quantQualityVals); - meta->quantQualityVals = NULL; + free_h264_metablock(meta); return error; } @@ -169,8 +166,7 @@ static UINT rdpgfx_decode_AVC420(RDPGFX_PLUGIN* gfx, RDPGFX_SURFACE_COMMAND* cmd WLog_ERR(TAG, "context->SurfaceCommand failed with error %" PRIu32 "", error); } - free(h264.meta.regionRects); - free(h264.meta.quantQualityVals); + free_h264_metablock(&h264.meta); return error; } @@ -259,10 +255,8 @@ static UINT rdpgfx_decode_AVC444(RDPGFX_PLUGIN* gfx, RDPGFX_SURFACE_COMMAND* cmd fail: Stream_Free(s, FALSE); - free(h264.bitstream[0].meta.regionRects); - free(h264.bitstream[0].meta.quantQualityVals); - free(h264.bitstream[1].meta.regionRects); - free(h264.bitstream[1].meta.quantQualityVals); + free_h264_metablock(&h264.bitstream[0].meta); + free_h264_metablock(&h264.bitstream[1].meta); return error; } diff --git a/include/freerdp/codec/h264.h b/include/freerdp/codec/h264.h index b8bc3c0c9..cfe0472f6 100644 --- a/include/freerdp/codec/h264.h +++ b/include/freerdp/codec/h264.h @@ -51,10 +51,12 @@ struct _H264_CONTEXT UINT32 NumberOfThreads; UINT32 iStride[3]; + BYTE* pOldYUVData[3]; BYTE* pYUVData[3]; UINT32 iYUV444Size[3]; UINT32 iYUV444Stride[3]; + BYTE* pOldYUV444Data[3]; BYTE* pYUV444Data[3]; UINT32 numSystemData; @@ -62,6 +64,10 @@ struct _H264_CONTEXT H264_CONTEXT_SUBSYSTEM* subsystem; YUV_CONTEXT* yuv; + BOOL encodingBuffer; + BOOL firstLumaFrameDone; + BOOL firstChromaFrameDone; + void* lumaData; wLog* log; }; @@ -70,9 +76,20 @@ extern "C" { #endif + static INLINE void free_h264_metablock(RDPGFX_H264_METABLOCK* meta) + { + RDPGFX_H264_METABLOCK m = { 0 }; + if (!meta) + return; + free(meta->quantQualityVals); + free(meta->regionRects); + *meta = m; + } + FREERDP_API INT32 avc420_compress(H264_CONTEXT* h264, const BYTE* pSrcData, DWORD SrcFormat, UINT32 nSrcStep, UINT32 nSrcWidth, UINT32 nSrcHeight, - BYTE** ppDstData, UINT32* pDstSize); + const RECTANGLE_16* regionRect, BYTE** ppDstData, + UINT32* pDstSize, RDPGFX_H264_METABLOCK* meta); FREERDP_API INT32 avc420_decompress(H264_CONTEXT* h264, const BYTE* pSrcData, UINT32 SrcSize, BYTE* pDstData, DWORD DstFormat, UINT32 nDstStep, @@ -81,8 +98,10 @@ extern "C" FREERDP_API INT32 avc444_compress(H264_CONTEXT* h264, const BYTE* pSrcData, DWORD SrcFormat, UINT32 nSrcStep, UINT32 nSrcWidth, UINT32 nSrcHeight, - BYTE version, BYTE* op, BYTE** pDstData, UINT32* pDstSize, - BYTE** pAuxDstData, UINT32* pAuxDstSize); + BYTE version, const RECTANGLE_16* regionRect, BYTE* op, + BYTE** pDstData, UINT32* pDstSize, BYTE** pAuxDstData, + UINT32* pAuxDstSize, RDPGFX_H264_METABLOCK* meta, + RDPGFX_H264_METABLOCK* auxMeta); FREERDP_API INT32 avc444_decompress(H264_CONTEXT* h264, BYTE op, const RECTANGLE_16* regionRects, UINT32 numRegionRect, diff --git a/libfreerdp/codec/h264.c b/libfreerdp/codec/h264.c index a9b46108c..30599842a 100644 --- a/libfreerdp/codec/h264.c +++ b/libfreerdp/codec/h264.c @@ -41,6 +41,9 @@ static BOOL avc444_ensure_buffer(H264_CONTEXT* h264, DWORD nDstHeight); BOOL avc420_ensure_buffer(H264_CONTEXT* h264, UINT32 stride, UINT32 width, UINT32 height) { + size_t x; + BOOL isNull = FALSE; + if (!h264) return FALSE; @@ -53,23 +56,33 @@ BOOL avc420_ensure_buffer(H264_CONTEXT* h264, UINT32 stride, UINT32 width, UINT3 if (height % 16 != 0) height += 16 - height % 16; - if (!h264->pYUVData[0] || !h264->pYUVData[1] || !h264->pYUVData[2] || (width != h264->width) || - (height != h264->height) || (stride != h264->iStride[0])) + for (x = 0; x < 3; x++) { + if (!h264->pYUVData[x] || !h264->pOldYUVData[x]) + isNull = TRUE; + } + + if (isNull || (width != h264->width) || (height != h264->height) || + (stride != h264->iStride[0])) + { + h264->iStride[0] = stride; h264->iStride[1] = (stride + 1) / 2; h264->iStride[2] = (stride + 1) / 2; h264->width = width; h264->height = height; - _aligned_free(h264->pYUVData[0]); - _aligned_free(h264->pYUVData[1]); - _aligned_free(h264->pYUVData[2]); - h264->pYUVData[0] = _aligned_malloc(h264->iStride[0] * height * 1ULL, 16); - h264->pYUVData[1] = _aligned_malloc(h264->iStride[1] * height * 1ULL, 16); - h264->pYUVData[2] = _aligned_malloc(h264->iStride[2] * height * 1ULL, 16); - if (!h264->pYUVData[0] || !h264->pYUVData[1] || !h264->pYUVData[2]) - return FALSE; + for (x = 0; x < 3; x++) + { + BYTE* tmp1 = _aligned_recalloc(h264->pYUVData[x], h264->iStride[x], height, 16); + BYTE* tmp2 = _aligned_recalloc(h264->pOldYUVData[x], h264->iStride[x], height, 16); + if (tmp1) + h264->pYUVData[x] = tmp1; + if (tmp2) + h264->pOldYUVData[x] = tmp2; + if (!tmp1 || !tmp2) + return FALSE; + } } return TRUE; @@ -82,7 +95,7 @@ INT32 avc420_decompress(H264_CONTEXT* h264, const BYTE* pSrcData, UINT32 SrcSize int status; const BYTE* pYUVData[3]; - if (!h264) + if (!h264 || h264->Compressor) return -1001; status = h264->subsystem->Decompress(h264, pSrcData, SrcSize); @@ -103,13 +116,117 @@ INT32 avc420_decompress(H264_CONTEXT* h264, const BYTE* pSrcData, UINT32 SrcSize return 1; } -INT32 avc420_compress(H264_CONTEXT* h264, const BYTE* pSrcData, DWORD SrcFormat, UINT32 nSrcStep, - UINT32 nSrcWidth, UINT32 nSrcHeight, BYTE** ppDstData, UINT32* pDstSize) +static BOOL allocate_h264_metablock(UINT32 QP, RECTANGLE_16* rectangles, + RDPGFX_H264_METABLOCK* meta, size_t count) { - RECTANGLE_16 rect; - const BYTE* pYUVData[3]; + size_t x; + if (!meta) + return FALSE; - if (!h264) + meta->regionRects = rectangles; + if (count == 0) + return TRUE; + + meta->quantQualityVals = calloc(count, sizeof(RDPGFX_H264_QUANT_QUALITY)); + + if (!meta->quantQualityVals || !meta->regionRects) + return FALSE; + meta->numRegionRects = count; + for (x = 0; x < count; x++) + { + RDPGFX_H264_QUANT_QUALITY* cur = &meta->quantQualityVals[x]; + cur->qp = QP; + cur->qualityVal = 100 - QP; + } + return TRUE; +} + +static INLINE BOOL diff_tile(const RECTANGLE_16* regionRect, BYTE* pYUVData[3], + BYTE* pOldYUVData[3], UINT32 const iStride[3]) +{ + size_t size, y; + if (!regionRect || !pYUVData || !pOldYUVData || !iStride) + return FALSE; + size = regionRect->right - regionRect->left; + if (regionRect->right > iStride[0]) + return FALSE; + if (regionRect->right / 2 > iStride[1]) + return FALSE; + if (regionRect->right / 2 > iStride[2]) + return FALSE; + + for (y = regionRect->top; y < regionRect->bottom; y++) + { + const BYTE* cur0 = &pYUVData[0][y * iStride[0]]; + const BYTE* cur1 = &pYUVData[1][y * iStride[1]]; + const BYTE* cur2 = &pYUVData[2][y * iStride[2]]; + const BYTE* old0 = &pOldYUVData[0][y * iStride[0]]; + const BYTE* old1 = &pOldYUVData[1][y * iStride[1]]; + const BYTE* old2 = &pOldYUVData[2][y * iStride[2]]; + + if (memcmp(&cur0[regionRect->left], &old0[regionRect->left], size) != 0) + return TRUE; + if (memcmp(&cur1[regionRect->left / 2], &old1[regionRect->left / 2], size / 2) != 0) + return TRUE; + if (memcmp(&cur2[regionRect->left / 2], &old2[regionRect->left / 2], size / 2) != 0) + return TRUE; + } + return FALSE; +} + +static BOOL detect_changes(BOOL firstFrameDone, const UINT32 QP, const RECTANGLE_16* regionRect, + BYTE* pYUVData[3], BYTE* pOldYUVData[3], UINT32 const iStride[3], + RDPGFX_H264_METABLOCK* meta) +{ + size_t count = 0, wc, hc; + RECTANGLE_16* rectangles; + + if (!regionRect || !pYUVData || !pOldYUVData || !iStride || !meta) + return FALSE; + + wc = (regionRect->right - regionRect->left) / 64 + 1; + hc = (regionRect->bottom - regionRect->top) / 64 + 1; + rectangles = calloc(wc * hc, sizeof(RECTANGLE_16)); + if (!rectangles) + return FALSE; + if (!firstFrameDone) + { + rectangles[0] = *regionRect; + count = 1; + } + else + { + size_t x, y; + for (y = regionRect->top; y < regionRect->bottom; y += 64) + { + for (x = regionRect->left; x < regionRect->right; x += 64) + { + RECTANGLE_16 rect; + rect.left = regionRect->left + x; + rect.top = regionRect->top + y; + rect.right = MIN(regionRect->left + x + 64, regionRect->right); + rect.bottom = MIN(regionRect->top + y + 64, regionRect->bottom); + if (diff_tile(&rect, pYUVData, pOldYUVData, iStride)) + rectangles[count++] = rect; + } + } + } + if (!allocate_h264_metablock(QP, rectangles, meta, count)) + return FALSE; + return TRUE; +} + +INT32 avc420_compress(H264_CONTEXT* h264, const BYTE* pSrcData, DWORD SrcFormat, UINT32 nSrcStep, + UINT32 nSrcWidth, UINT32 nSrcHeight, const RECTANGLE_16* regionRect, + BYTE** ppDstData, UINT32* pDstSize, RDPGFX_H264_METABLOCK* meta) +{ + size_t x; + INT32 rc; + BYTE* pYUVData[3]; + const BYTE* pcYUVData[3]; + BYTE* pOldYUVData[3]; + + if (!h264 || !regionRect || !meta || !h264->Compressor) return -1; if (!h264->subsystem->Compress) @@ -118,30 +235,58 @@ INT32 avc420_compress(H264_CONTEXT* h264, const BYTE* pSrcData, DWORD SrcFormat, if (!avc420_ensure_buffer(h264, nSrcStep, nSrcWidth, nSrcHeight)) return -1; - rect.left = 0; - rect.top = 0; - rect.right = nSrcWidth; - rect.bottom = nSrcHeight; + if (h264->encodingBuffer) + { + for (x = 0; x < 3; x++) + { + pYUVData[x] = h264->pYUVData[x]; + pOldYUVData[x] = h264->pOldYUVData[x]; + } + } + else + { + for (x = 0; x < 3; x++) + { + pYUVData[x] = h264->pOldYUVData[x]; + pOldYUVData[x] = h264->pYUVData[x]; + } + } + h264->encodingBuffer = !h264->encodingBuffer; - if (!yuv420_context_encode(h264->yuv, pSrcData, nSrcStep, SrcFormat, h264->iStride, - h264->pYUVData, &rect, 1)) + if (!yuv420_context_encode(h264->yuv, pSrcData, nSrcStep, SrcFormat, h264->iStride, pYUVData, + regionRect, 1)) return -1; - pYUVData[0] = h264->pYUVData[0]; - pYUVData[1] = h264->pYUVData[1]; - pYUVData[2] = h264->pYUVData[2]; - return h264->subsystem->Compress(h264, pYUVData, h264->iStride, ppDstData, pDstSize); + if (!detect_changes(h264->firstLumaFrameDone, h264->QP, regionRect, pYUVData, pOldYUVData, + h264->iStride, meta)) + return -1; + + if (meta->numRegionRects == 0) + return 0; + + for (x = 0; x < 3; x++) + pcYUVData[x] = pYUVData[x]; + + rc = h264->subsystem->Compress(h264, pcYUVData, h264->iStride, ppDstData, pDstSize); + if (rc >= 0) + h264->firstLumaFrameDone = TRUE; + return rc; } INT32 avc444_compress(H264_CONTEXT* h264, const BYTE* pSrcData, DWORD SrcFormat, UINT32 nSrcStep, - UINT32 nSrcWidth, UINT32 nSrcHeight, BYTE version, BYTE* op, BYTE** ppDstData, - UINT32* pDstSize, BYTE** ppAuxDstData, UINT32* pAuxDstSize) + UINT32 nSrcWidth, UINT32 nSrcHeight, BYTE version, const RECTANGLE_16* region, + BYTE* op, BYTE** ppDstData, UINT32* pDstSize, BYTE** ppAuxDstData, + UINT32* pAuxDstSize, RDPGFX_H264_METABLOCK* meta, + RDPGFX_H264_METABLOCK* auxMeta) { - RECTANGLE_16 rect = { 0 }; BYTE* coded; UINT32 codedSize; + BYTE** pYUV444Data; + BYTE** pOldYUV444Data; + BYTE** pYUVData; + BYTE** pOldYUVData; - if (!h264) + if (!h264 || !h264->Compressor) return -1; if (!h264->subsystem->Compress) @@ -153,34 +298,75 @@ INT32 avc444_compress(H264_CONTEXT* h264, const BYTE* pSrcData, DWORD SrcFormat, if (!avc444_ensure_buffer(h264, nSrcHeight)) return -1; - rect.right = nSrcWidth; - rect.bottom = nSrcHeight; + if (h264->encodingBuffer) + { + pYUV444Data = h264->pOldYUV444Data; + pOldYUV444Data = h264->pYUV444Data; + pYUVData = h264->pOldYUVData; + pOldYUVData = h264->pYUVData; + } + else + { + pYUV444Data = h264->pYUV444Data; + pOldYUV444Data = h264->pOldYUV444Data; + pYUVData = h264->pYUVData; + pOldYUVData = h264->pOldYUVData; + } + h264->encodingBuffer = !h264->encodingBuffer; if (!yuv444_context_encode(h264->yuv, version, pSrcData, nSrcStep, SrcFormat, h264->iStride, - h264->pYUV444Data, h264->pYUVData, &rect, 1)) + pYUV444Data, pYUVData, region, 1)) return -1; - { - const BYTE* pYUV444Data[3] = { h264->pYUV444Data[0], h264->pYUV444Data[1], - h264->pYUV444Data[2] }; + if (!detect_changes(h264->firstLumaFrameDone, h264->QP, region, pYUV444Data, pOldYUV444Data, + h264->iStride, meta)) + return -1; + if (!detect_changes(h264->firstChromaFrameDone, h264->QP, region, pYUVData, pOldYUVData, + h264->iStride, auxMeta)) + return -1; - if (h264->subsystem->Compress(h264, pYUV444Data, h264->iStride, &coded, &codedSize) < 0) - return -1; + /* [MS-RDPEGFX] 2.2.4.5 RFX_AVC444_BITMAP_STREAM + * LC: + * 0 ... Luma & Chroma + * 1 ... Luma + * 2 ... Chroma + */ + if ((meta->numRegionRects > 0) && (auxMeta->numRegionRects > 0)) + *op = 0; + else if (meta->numRegionRects > 0) + *op = 1; + else if (auxMeta->numRegionRects > 0) + *op = 2; + else + { + WLog_INFO(TAG, "no changes detected for luma or chroma frame"); + return 0; } - memcpy(h264->lumaData, coded, codedSize); - *ppDstData = h264->lumaData; - *pDstSize = codedSize; + if ((*op == 0) || (*op == 1)) { - const BYTE* pYUVData[3] = { h264->pYUVData[0], h264->pYUVData[1], h264->pYUVData[2] }; + const BYTE* pcYUV444Data[3] = { pYUV444Data[0], pYUV444Data[1], pYUV444Data[2] }; - if (h264->subsystem->Compress(h264, pYUVData, h264->iStride, &coded, &codedSize) < 0) + if (h264->subsystem->Compress(h264, pcYUV444Data, h264->iStride, &coded, &codedSize) < 0) return -1; + h264->firstLumaFrameDone = TRUE; + memcpy(h264->lumaData, coded, codedSize); + *ppDstData = h264->lumaData; + *pDstSize = codedSize; } - *ppAuxDstData = coded; - *pAuxDstSize = codedSize; - *op = 0; - return 0; + + if ((*op == 0) || (*op == 2)) + { + const BYTE* pcYUVData[3] = { pYUVData[0], pYUVData[1], pYUVData[2] }; + + if (h264->subsystem->Compress(h264, pcYUVData, h264->iStride, &coded, &codedSize) < 0) + return -1; + h264->firstChromaFrameDone = TRUE; + *ppAuxDstData = coded; + *pAuxDstSize = codedSize; + } + + return 1; } static BOOL avc444_ensure_buffer(H264_CONTEXT* h264, DWORD nDstHeight) @@ -190,6 +376,7 @@ static BOOL avc444_ensure_buffer(H264_CONTEXT* h264, DWORD nDstHeight) UINT32* piDstSize = h264->iYUV444Size; UINT32* piDstStride = h264->iYUV444Stride; BYTE** ppYUVDstData = h264->pYUV444Data; + BYTE** ppOldYUVDstData = h264->pOldYUV444Data; const UINT32 pad = nDstHeight % 16; UINT32 padDstHeight = nDstHeight; /* Need alignment to 16x16 blocks */ @@ -200,24 +387,31 @@ static BOOL avc444_ensure_buffer(H264_CONTEXT* h264, DWORD nDstHeight) { for (x = 0; x < 3; x++) { + BYTE* tmp1; + BYTE* tmp2; piDstStride[x] = piMainStride[0]; piDstSize[x] = piDstStride[x] * padDstHeight; - _aligned_free(ppYUVDstData[x]); - ppYUVDstData[x] = _aligned_malloc(piDstSize[x], 16); - - if (!ppYUVDstData[x]) + tmp1 = _aligned_recalloc(ppYUVDstData[x], piDstSize[x], 1, 16); + if (tmp1) + ppYUVDstData[x] = tmp1; + tmp2 = _aligned_recalloc(ppOldYUVDstData[x], piDstSize[x], 1, 16); + if (tmp2) + ppOldYUVDstData[x] = tmp2; + if (!tmp1 || !tmp2) goto fail; - - memset(ppYUVDstData[x], 0, piDstSize[x]); } - _aligned_free(h264->lumaData); - h264->lumaData = _aligned_malloc(piDstSize[0] * 4, 16); + { + BYTE* tmp = _aligned_recalloc(h264->lumaData, piDstSize[0], 4, 16); + if (!tmp) + goto fail; + h264->lumaData = tmp; + } } for (x = 0; x < 3; x++) { - if (!ppYUVDstData[x] || (piDstSize[x] == 0) || (piDstStride[x] == 0)) + if (!ppOldYUVDstData[x] || !ppYUVDstData[x] || (piDstSize[x] == 0) || (piDstStride[x] == 0)) { WLog_Print(h264->log, WLOG_ERROR, "YUV buffer not initialized! check your decoder settings"); @@ -230,14 +424,6 @@ static BOOL avc444_ensure_buffer(H264_CONTEXT* h264, DWORD nDstHeight) return TRUE; fail: - _aligned_free(ppYUVDstData[0]); - _aligned_free(ppYUVDstData[1]); - _aligned_free(ppYUVDstData[2]); - _aligned_free(h264->lumaData); - ppYUVDstData[0] = NULL; - ppYUVDstData[1] = NULL; - ppYUVDstData[2] = NULL; - h264->lumaData = NULL; return FALSE; } @@ -297,7 +483,7 @@ INT32 avc444_decompress(H264_CONTEXT* h264, BYTE op, const RECTANGLE_16* regionR avc444_frame_type chroma = (codecId == RDPGFX_CODECID_AVC444) ? AVC444_CHROMAv1 : AVC444_CHROMAv2; - if (!h264 || !regionRects || !pSrcData || !pDstData) + if (!h264 || !regionRects || !pSrcData || !pDstData || h264->Compressor) return -1001; switch (op) @@ -487,11 +673,21 @@ void h264_context_free(H264_CONTEXT* h264) { if (h264) { + size_t x; h264->subsystem->Uninit(h264); - _aligned_free(h264->pYUV444Data[0]); - _aligned_free(h264->pYUV444Data[1]); - _aligned_free(h264->pYUV444Data[2]); + + for (x = 0; x < 3; x++) + { + if (h264->Compressor) + { + _aligned_free(h264->pYUVData[x]); + _aligned_free(h264->pOldYUVData[x]); + } + _aligned_free(h264->pYUV444Data[x]); + _aligned_free(h264->pOldYUV444Data[x]); + } _aligned_free(h264->lumaData); + yuv_context_free(h264->yuv); free(h264); } diff --git a/libfreerdp/codec/yuv.c b/libfreerdp/codec/yuv.c index c04fd4201..dc5bbd2dd 100644 --- a/libfreerdp/codec/yuv.c +++ b/libfreerdp/codec/yuv.c @@ -191,6 +191,10 @@ static INLINE YUV_PROCESS_WORK_PARAM pool_decode_param(const RECTANGLE_16* rect, static BOOL allocate_objects(PTP_WORK** work, void** params, size_t size, UINT32 count) { + if (count == 0) + return FALSE; + + count *= 2; { PTP_WORK* tmp; PTP_WORK* cur = *work; @@ -198,12 +202,14 @@ static BOOL allocate_objects(PTP_WORK** work, void** params, size_t size, UINT32 if (!tmp) return FALSE; *work = tmp; + memset(tmp, 0, sizeof(PTP_WORK*) * count); } { void* cur = *params; void* tmp = realloc(cur, size * count); if (!tmp) return FALSE; + memset(tmp, 0, size * count); *params = tmp; } return TRUE; @@ -225,11 +231,16 @@ static BOOL submit_object(PTP_WORK* work_object, PTP_WORK_CALLBACK cb, const voi static void free_objects(PTP_WORK* work_objects, void* params, UINT32 waitCount) { - UINT32 i; - for (i = 0; i < waitCount; i++) + if (work_objects) { - WaitForThreadpoolWorkCallbacks(work_objects[i], FALSE); - CloseThreadpoolWork(work_objects[i]); + UINT32 i; + for (i = 0; i < waitCount; i++) + { + if (!work_objects[i]) + continue; + WaitForThreadpoolWorkCallbacks(work_objects[i], FALSE); + CloseThreadpoolWork(work_objects[i]); + } } free(work_objects); @@ -260,6 +271,17 @@ static BOOL pool_decode(YUV_CONTEXT* context, PTP_WORK_CALLBACK cb, const BYTE* /* case where we use threads */ nobjects = (context->height + context->heightStep - 1) / context->heightStep; + for (x = 0; x < numRegionRects; x++) + { + const RECTANGLE_16* rect = ®ionRects[x]; + const UINT32 height = rect->bottom - rect->top; + const UINT32 steps = (height + context->heightStep / 2) / context->heightStep; + + if (waitCount + steps >= nobjects) + nobjects *= 2; + waitCount += steps; + } + if (!allocate_objects(&work_objects, (void**)¶ms, sizeof(YUV_PROCESS_WORK_PARAM), nobjects)) goto fail; @@ -269,14 +291,6 @@ static BOOL pool_decode(YUV_CONTEXT* context, PTP_WORK_CALLBACK cb, const BYTE* const UINT32 height = rect->bottom - rect->top; const UINT32 steps = (height + context->heightStep / 2) / context->heightStep; - if (waitCount + steps >= nobjects) - { - nobjects *= 2; - if (!allocate_objects(&work_objects, (void**)¶ms, sizeof(YUV_PROCESS_WORK_PARAM), - nobjects)) - goto fail; - } - for (y = 0; y < steps; y++) { YUV_PROCESS_WORK_PARAM* cur = ¶ms[waitCount]; @@ -589,6 +603,17 @@ static BOOL pool_encode(YUV_CONTEXT* context, PTP_WORK_CALLBACK cb, const BYTE* /* case where we use threads */ nobjects = (context->height + context->heightStep - 1) / context->heightStep; + for (x = 0; x < numRegionRects; x++) + { + const RECTANGLE_16* rect = ®ionRects[x]; + const UINT32 height = rect->bottom - rect->top; + const UINT32 steps = (height + context->heightStep / 2) / context->heightStep; + + if (waitCount + steps >= nobjects) + nobjects *= 2; + waitCount += steps; + } + if (!allocate_objects(&work_objects, (void**)¶ms, sizeof(YUV_ENCODE_WORK_PARAM), nobjects)) goto fail; @@ -598,14 +623,6 @@ static BOOL pool_encode(YUV_CONTEXT* context, PTP_WORK_CALLBACK cb, const BYTE* const UINT32 height = rect->bottom - rect->top; const UINT32 steps = (height + context->heightStep / 2) / context->heightStep; - if (waitCount + steps >= nobjects) - { - nobjects *= 2; - if (!allocate_objects(&work_objects, (void**)¶ms, sizeof(YUV_ENCODE_WORK_PARAM), - nobjects)) - goto fail; - } - for (y = 0; y < steps; y++) { RECTANGLE_16 r = *rect; diff --git a/libfreerdp/primitives/prim_YUV_ssse3.c b/libfreerdp/primitives/prim_YUV_ssse3.c index 8c8fa962f..ef438a28d 100644 --- a/libfreerdp/primitives/prim_YUV_ssse3.c +++ b/libfreerdp/primitives/prim_YUV_ssse3.c @@ -436,7 +436,8 @@ static INLINE void ssse3_RGBToYUV420_BGRX_UV(const BYTE* src1, const BYTE* src2, } static pstatus_t ssse3_RGBToYUV420_BGRX(const BYTE* pSrc, UINT32 srcFormat, UINT32 srcStep, - BYTE* pDst[3], UINT32 dstStep[3], const prim_size_t* roi) + BYTE* pDst[3], const UINT32 dstStep[3], + const prim_size_t* roi) { UINT32 y; const BYTE* argb = pSrc; @@ -478,7 +479,7 @@ static pstatus_t ssse3_RGBToYUV420_BGRX(const BYTE* pSrc, UINT32 srcFormat, UINT } static pstatus_t ssse3_RGBToYUV420(const BYTE* pSrc, UINT32 srcFormat, UINT32 srcStep, - BYTE* pDst[3], UINT32 dstStep[3], const prim_size_t* roi) + BYTE* pDst[3], const UINT32 dstStep[3], const prim_size_t* roi) { switch (srcFormat) { diff --git a/server/shadow/shadow_client.c b/server/shadow/shadow_client.c index a5826cd4b..22224f62d 100644 --- a/server/shadow/shadow_client.c +++ b/server/shadow/shadow_client.c @@ -828,9 +828,9 @@ static BOOL shadow_client_send_surface_gfx(rdpShadowClient* client, const BYTE* if (settings->GfxAVC444 || settings->GfxAVC444v2) { - RDPGFX_AVC444_BITMAP_STREAM avc444; - RECTANGLE_16 regionRect; - RDPGFX_H264_QUANT_QUALITY quantQualityVal; + INT32 rc; + RDPGFX_AVC444_BITMAP_STREAM avc444 = { 0 }; + RECTANGLE_16 regionRect = { 0 }; BYTE version = settings->GfxAVC444v2 ? 2 : 1; if (shadow_encoder_prepare(encoder, FREERDP_CODEC_AVC444) < 0) @@ -839,34 +839,33 @@ static BOOL shadow_client_send_surface_gfx(rdpShadowClient* client, const BYTE* return FALSE; } - if (avc444_compress(encoder->h264, pSrcData, cmd.format, nSrcStep, nWidth, nHeight, version, - &avc444.LC, &avc444.bitstream[0].data, &avc444.bitstream[0].length, - &avc444.bitstream[1].data, &avc444.bitstream[1].length) < 0) + regionRect.left = cmd.left; + regionRect.top = cmd.top; + regionRect.right = cmd.right; + regionRect.bottom = cmd.bottom; + rc = avc444_compress(encoder->h264, pSrcData, cmd.format, nSrcStep, nWidth, nHeight, + version, ®ionRect, &avc444.LC, &avc444.bitstream[0].data, + &avc444.bitstream[0].length, &avc444.bitstream[1].data, + &avc444.bitstream[1].length, &avc444.bitstream[0].meta, + &avc444.bitstream[1].meta); + if (rc < 0) { WLog_ERR(TAG, "avc420_compress failed for avc444"); return FALSE; } - regionRect.left = cmd.left; - regionRect.top = cmd.top; - regionRect.right = cmd.right; - regionRect.bottom = cmd.bottom; - quantQualityVal.qp = encoder->h264->QP; - quantQualityVal.r = 0; - quantQualityVal.p = 0; - quantQualityVal.qualityVal = 100 - quantQualityVal.qp; - avc444.bitstream[0].meta.numRegionRects = 1; - avc444.bitstream[0].meta.regionRects = ®ionRect; - avc444.bitstream[0].meta.quantQualityVals = &quantQualityVal; - avc444.bitstream[1].meta.numRegionRects = 1; - avc444.bitstream[1].meta.regionRects = ®ionRect; - avc444.bitstream[1].meta.quantQualityVals = &quantQualityVal; - avc444.cbAvc420EncodedBitstream1 = rdpgfx_estimate_h264_avc420(&avc444.bitstream[0]); - cmd.codecId = settings->GfxAVC444v2 ? RDPGFX_CODECID_AVC444v2 : RDPGFX_CODECID_AVC444; - cmd.extra = (void*)&avc444; - IFCALLRET(client->rdpgfx->SurfaceFrameCommand, error, client->rdpgfx, &cmd, &cmdstart, - &cmdend); + /* rc > 0 means new data */ + if (rc > 0) + { + avc444.cbAvc420EncodedBitstream1 = rdpgfx_estimate_h264_avc420(&avc444.bitstream[0]); + cmd.codecId = settings->GfxAVC444v2 ? RDPGFX_CODECID_AVC444v2 : RDPGFX_CODECID_AVC444; + cmd.extra = (void*)&avc444; + IFCALLRET(client->rdpgfx->SurfaceFrameCommand, error, client->rdpgfx, &cmd, &cmdstart, + &cmdend); + } + free_h264_metablock(&avc444.bitstream[0].meta); + free_h264_metablock(&avc444.bitstream[1].meta); if (error) { WLog_ERR(TAG, "SurfaceFrameCommand failed with error %" PRIu32 "", error); @@ -875,9 +874,9 @@ static BOOL shadow_client_send_surface_gfx(rdpShadowClient* client, const BYTE* } else if (settings->GfxH264) { - RDPGFX_AVC420_BITMAP_STREAM avc420; + INT32 rc; + RDPGFX_AVC420_BITMAP_STREAM avc420 = { 0 }; RECTANGLE_16 regionRect; - RDPGFX_H264_QUANT_QUALITY quantQualityVal; if (shadow_encoder_prepare(encoder, FREERDP_CODEC_AVC420) < 0) { @@ -885,28 +884,28 @@ static BOOL shadow_client_send_surface_gfx(rdpShadowClient* client, const BYTE* return FALSE; } - if (avc420_compress(encoder->h264, pSrcData, cmd.format, nSrcStep, nWidth, nHeight, - &avc420.data, &avc420.length) < 0) + regionRect.left = cmd.left; + regionRect.top = cmd.top; + regionRect.right = cmd.right; + regionRect.bottom = cmd.bottom; + rc = avc420_compress(encoder->h264, pSrcData, cmd.format, nSrcStep, nWidth, nHeight, + ®ionRect, &avc420.data, &avc420.length, &avc420.meta); + if (rc < 0) { WLog_ERR(TAG, "avc420_compress failed"); return FALSE; } - cmd.codecId = RDPGFX_CODECID_AVC420; - cmd.extra = (void*)&avc420; - regionRect.left = cmd.left; - regionRect.top = cmd.top; - regionRect.right = cmd.right; - regionRect.bottom = cmd.bottom; - quantQualityVal.qp = encoder->h264->QP; - quantQualityVal.r = 0; - quantQualityVal.p = 0; - quantQualityVal.qualityVal = 100 - quantQualityVal.qp; - avc420.meta.numRegionRects = 1; - avc420.meta.regionRects = ®ionRect; - avc420.meta.quantQualityVals = &quantQualityVal; - IFCALLRET(client->rdpgfx->SurfaceFrameCommand, error, client->rdpgfx, &cmd, &cmdstart, - &cmdend); + /* rc > 0 means new data */ + if (rc > 0) + { + cmd.codecId = RDPGFX_CODECID_AVC420; + cmd.extra = (void*)&avc420; + + IFCALLRET(client->rdpgfx->SurfaceFrameCommand, error, client->rdpgfx, &cmd, &cmdstart, + &cmdend); + } + free_h264_metablock(&avc420.meta); if (error) { diff --git a/winpr/libwinpr/crt/alignment.c b/winpr/libwinpr/crt/alignment.c index af76023d7..51da5df06 100644 --- a/winpr/libwinpr/crt/alignment.c +++ b/winpr/libwinpr/crt/alignment.c @@ -160,12 +160,19 @@ void* _aligned_offset_realloc(void* memblock, size_t size, size_t alignment, siz return newMemblock; } +static INLINE size_t cMIN(size_t a, size_t b) +{ + if (a > b) + return b; + return a; +} + void* _aligned_offset_recalloc(void* memblock, size_t num, size_t size, size_t alignment, size_t offset) { - void* newMemblock; - WINPR_ALIGNED_MEM* pMem; - WINPR_ALIGNED_MEM* pNewMem; + void* newMemblock = NULL; + WINPR_ALIGNED_MEM* pMem = NULL; + WINPR_ALIGNED_MEM* pNewMem = NULL; if (!memblock) { @@ -186,22 +193,24 @@ void* _aligned_offset_recalloc(void* memblock, size_t num, size_t size, size_t a { WLog_ERR(TAG, "_aligned_offset_recalloc: memory block was not allocated by _aligned_malloc!"); - return NULL; + goto fail; } if (size == 0) - { - _aligned_free(memblock); - return NULL; - } + goto fail; newMemblock = _aligned_offset_malloc(size * num, alignment, offset); if (!newMemblock) - return NULL; + goto fail; pNewMem = WINPR_ALIGNED_MEM_STRUCT_FROM_PTR(newMemblock); - ZeroMemory(newMemblock, pNewMem->size); + { + const size_t size = cMIN(pMem->size, pNewMem->size); + memcpy(newMemblock, pMem->base_addr, size); + ZeroMemory(newMemblock + size, pNewMem->size - size); + } +fail: _aligned_free(memblock); return newMemblock; }