diff --git a/channels/rdpgfx/server/rdpgfx_main.c b/channels/rdpgfx/server/rdpgfx_main.c index 609b308d8..b87febdb0 100644 --- a/channels/rdpgfx/server/rdpgfx_main.c +++ b/channels/rdpgfx/server/rdpgfx_main.c @@ -508,6 +508,7 @@ static UINT rdpgfx_write_h264_metablock(wStream* s, RDPGFX_H264_METABLOCK* meta) RECTANGLE_16* regionRect; RDPGFX_H264_QUANT_QUALITY* quantQualityVal; UINT error = CHANNEL_RC_OK; + Stream_EnsureRemainingCapacity(s, 4 + meta->numRegionRects * 10); Stream_Write_UINT32(s, meta->numRegionRects); /* numRegionRects (4 bytes) */ for (index = 0; index < meta->numRegionRects; index++) @@ -552,6 +553,7 @@ static INLINE UINT rdpgfx_write_h264_avc420(wStream* s, return error; } + Stream_EnsureRemainingCapacity(s, havc420->length); Stream_Write(s, havc420->data, havc420->length); return error; } @@ -623,7 +625,7 @@ static UINT rdpgfx_write_surface_command(wStream* s, return error; } } - else if (cmd->codecId == RDPGFX_CODECID_AVC444) + else if ((cmd->codecId == RDPGFX_CODECID_AVC444) || (cmd->codecId == RDPGFX_CODECID_AVC444v2)) { havc444 = (RDPGFX_AVC444_BITMAP_STREAM*)cmd->extra; havc420 = &(havc444->bitstream[0]); /* avc420EncodedBitstreamInfo (4 bytes) */ @@ -655,7 +657,6 @@ static UINT rdpgfx_write_surface_command(wStream* s, Stream_Write(s, cmd->data, cmd->length); } - assert(Stream_GetPosition(s) <= Stream_Capacity(s)); /* Fill actual bitmap data length */ bitmapDataLength = Stream_GetPosition(s) - bitmapDataStart; Stream_SetPosition(s, bitmapDataStart - sizeof(UINT32)); @@ -1332,7 +1333,6 @@ static void* rdpgfx_server_thread_func(void* arg) UINT error = CHANNEL_RC_OK; buffer = NULL; nCount = 0; - events[nCount++] = priv->stopEvent; events[nCount++] = priv->channelEvent; diff --git a/include/freerdp/codec/h264.h b/include/freerdp/codec/h264.h index e805092a3..292de2632 100644 --- a/include/freerdp/codec/h264.h +++ b/include/freerdp/codec/h264.h @@ -31,8 +31,9 @@ typedef void (*pfnH264SubsystemUninit)(H264_CONTEXT* h264); typedef int (*pfnH264SubsystemDecompress)(H264_CONTEXT* h264, const BYTE* pSrcData, UINT32 SrcSize); -typedef int (*pfnH264SubsystemCompress)(H264_CONTEXT* h264, BYTE** ppDstData, - UINT32* pDstSize); +typedef int (*pfnH264SubsystemCompress)(H264_CONTEXT* h264, const BYTE** pSrcYuv, + const UINT32* pStride, + BYTE** ppDstData, UINT32* pDstSize); struct _H264_CONTEXT_SUBSYSTEM { @@ -74,6 +75,8 @@ struct _H264_CONTEXT UINT32 numSystemData; void* pSystemData; H264_CONTEXT_SUBSYSTEM* subsystem; + + void* lumaData; }; #ifdef __cplusplus @@ -93,7 +96,7 @@ FREERDP_API INT32 avc420_decompress(H264_CONTEXT* h264, const BYTE* pSrcData, FREERDP_API INT32 avc444_compress(H264_CONTEXT* h264, const BYTE* pSrcData, DWORD SrcFormat, UINT32 nSrcStep, UINT32 nSrcWidth, UINT32 nSrcHeight, - BYTE* op, + BYTE version, BYTE* op, BYTE** pDstData, UINT32* pDstSize, BYTE** pAuxDstData, UINT32* pAuxDstSize); diff --git a/include/freerdp/settings.h b/include/freerdp/settings.h index b8fdfa5c5..e0157417a 100644 --- a/include/freerdp/settings.h +++ b/include/freerdp/settings.h @@ -1344,7 +1344,8 @@ struct rdp_settings ALIGN64 BOOL GfxH264; /* 3844 */ ALIGN64 BOOL GfxAVC444; /* 3845 */ ALIGN64 BOOL GfxSendQoeAck; /* 3846 */ - UINT64 padding3904[3904 - 3847]; /* 3847 */ + ALIGN64 BOOL GfxAVC444v2; /* 3847 */ + UINT64 padding3904[3904 - 3848]; /* 3848 */ /** * Caches diff --git a/libfreerdp/codec/h264.c b/libfreerdp/codec/h264.c index 357465d8f..f5481821d 100644 --- a/libfreerdp/codec/h264.c +++ b/libfreerdp/codec/h264.c @@ -32,8 +32,12 @@ #include #include +#include "h264.h" + #define TAG FREERDP_TAG("codec") +static BOOL avc444_ensure_buffer(H264_CONTEXT* h264, DWORD nDstHeight); + BOOL avc420_ensure_buffer(H264_CONTEXT* h264, UINT32 stride, UINT32 width, UINT32 height) { if (!h264) @@ -43,14 +47,13 @@ BOOL avc420_ensure_buffer(H264_CONTEXT* h264, UINT32 stride, UINT32 width, UINT3 stride = width; if (!h264->pYUVData[0] || !h264->pYUVData[1] || !h264->pYUVData[2] || - (width != h264->width) || (height != h264->height) || (stride != h264->iStride[0])) + (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]); @@ -203,19 +206,73 @@ INT32 avc420_compress(H264_CONTEXT* h264, const BYTE* pSrcData, DWORD SrcFormat, roi.width = nSrcWidth; roi.height = nSrcHeight; + if (prims->RGBToYUV420_8u_P3AC4R(pSrcData, SrcFormat, nSrcStep, h264->pYUVData, h264->iStride, - &roi) != PRIMITIVES_SUCCESS) + &roi) != PRIMITIVES_SUCCESS) return -1; - return h264->subsystem->Compress(h264, ppDstData, pDstSize); + return h264->subsystem->Compress(h264, h264->pYUVData, h264->iStride, ppDstData, pDstSize); } INT32 avc444_compress(H264_CONTEXT* h264, const BYTE* pSrcData, DWORD SrcFormat, UINT32 nSrcStep, UINT32 nSrcWidth, UINT32 nSrcHeight, - BYTE* op, BYTE** ppDstData, UINT32* pDstSize, + BYTE version, BYTE* op, BYTE** ppDstData, UINT32* pDstSize, BYTE** ppAuxDstData, UINT32* pAuxDstSize) { - return -1; + prim_size_t roi; + primitives_t* prims = primitives_get(); + BYTE* coded; + UINT32 codedSize; + + if (!h264) + return -1; + + if (!h264->subsystem->Compress) + return -1; + + if (!avc420_ensure_buffer(h264, nSrcStep, nSrcWidth, nSrcHeight)) + return -1; + + if (!avc444_ensure_buffer(h264, nSrcHeight)) + return -1; + + roi.width = nSrcWidth; + roi.height = nSrcHeight; + + switch (version) + { + case 1: + if (prims->RGBToAVC444YUV(pSrcData, SrcFormat, nSrcStep, h264->pYUV444Data, h264->iStride, + h264->pYUVData, h264->iStride, &roi) != PRIMITIVES_SUCCESS) + return -1; + + break; + + case 2: + if (prims->RGBToAVC444YUVv2(pSrcData, SrcFormat, nSrcStep, h264->pYUV444Data, h264->iStride, + h264->pYUVData, h264->iStride, &roi) != PRIMITIVES_SUCCESS) + return -1; + + break; + + default: + return -1; + } + + if (h264->subsystem->Compress(h264, h264->pYUV444Data, h264->iStride, &coded, &codedSize) < 0) + return -1; + + memcpy(h264->lumaData, coded, codedSize); + *ppDstData = h264->lumaData; + *pDstSize = codedSize; + + if (h264->subsystem->Compress(h264, h264->pYUVData, h264->iStride, &coded, &codedSize) < 0) + return -1; + + *ppAuxDstData = coded; + *pAuxDstSize = codedSize; + *op = 0; + return 0; } static BOOL avc444_ensure_buffer(H264_CONTEXT* h264, @@ -243,6 +300,9 @@ static BOOL avc444_ensure_buffer(H264_CONTEXT* h264, memset(ppYUVDstData[x], 0, piDstSize[x]); } + + _aligned_free(h264->lumaData); + h264->lumaData = _aligned_malloc(piDstSize[0] * 4, 16); } for (x = 0; x < 3; x++) @@ -259,9 +319,11 @@ 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; } @@ -409,23 +471,22 @@ INT32 avc444_decompress(H264_CONTEXT* h264, BYTE op, #define MAX_SUBSYSTEMS 10 static INIT_ONCE subsystems_once = INIT_ONCE_STATIC_INIT; -static H264_CONTEXT_SUBSYSTEM *subSystems[MAX_SUBSYSTEMS]; +static H264_CONTEXT_SUBSYSTEM* subSystems[MAX_SUBSYSTEMS]; #if defined(_WIN32) && defined(WITH_MEDIA_FOUNDATION) extern H264_CONTEXT_SUBSYSTEM g_Subsystem_MF; #endif -static BOOL CALLBACK h264_register_subsystems(PINIT_ONCE once, PVOID param, PVOID *context) { +static BOOL CALLBACK h264_register_subsystems(PINIT_ONCE once, PVOID param, PVOID* context) +{ int i = 0; ZeroMemory(subSystems, sizeof(subSystems)); - #if defined(_WIN32) && defined(WITH_MEDIA_FOUNDATION) { subSystems[i] = &g_Subsystem_MF; i++; } #endif - #ifdef WITH_OPENH264 { extern H264_CONTEXT_SUBSYSTEM g_Subsystem_OpenH264; @@ -433,7 +494,6 @@ static BOOL CALLBACK h264_register_subsystems(PINIT_ONCE once, PVOID param, PVOI i++; } #endif - #ifdef WITH_FFMPEG { extern H264_CONTEXT_SUBSYSTEM g_Subsystem_libavcodec; @@ -441,7 +501,6 @@ static BOOL CALLBACK h264_register_subsystems(PINIT_ONCE once, PVOID param, PVOI i++; } #endif - #ifdef WITH_X264 { extern H264_CONTEXT_SUBSYSTEM g_Subsystem_x264; @@ -449,7 +508,6 @@ static BOOL CALLBACK h264_register_subsystems(PINIT_ONCE once, PVOID param, PVOI i++; } #endif - return i > 0; } @@ -462,12 +520,12 @@ BOOL h264_context_init(H264_CONTEXT* h264) return FALSE; h264->subsystem = NULL; - InitOnceExecuteOnce(&subsystems_once, h264_register_subsystems, NULL, NULL); for (i = 0; i < MAX_SUBSYSTEMS; i++) { H264_CONTEXT_SUBSYSTEM* subsystem = subSystems[i]; + if (!subsystem || !subsystem->Init) break; @@ -525,6 +583,7 @@ void h264_context_free(H264_CONTEXT* h264) _aligned_free(h264->pYUV444Data[0]); _aligned_free(h264->pYUV444Data[1]); _aligned_free(h264->pYUV444Data[2]); + _aligned_free(h264->lumaData); free(h264); } } diff --git a/libfreerdp/codec/h264.h b/libfreerdp/codec/h264.h new file mode 100644 index 000000000..f87d17ad2 --- /dev/null +++ b/libfreerdp/codec/h264.h @@ -0,0 +1,31 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * RemoteFX Codec Library - Decode + * + * Copyright 2018 Armin Novak + * Copyright 2018 Thincast Technologies GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FREERDP_LIB_CODEC_H264_H +#define FREERDP_LIB_CODEC_H264_H + +#include +#include + +FREERDP_LOCAL BOOL avc420_ensure_buffer(H264_CONTEXT* h264, + UINT32 stride, UINT32 width, UINT32 height); + +#endif /* FREERDP_LIB_CODEC_H264_H */ + diff --git a/libfreerdp/codec/h264_ffmpeg.c b/libfreerdp/codec/h264_ffmpeg.c index 3107769b3..ef278638a 100644 --- a/libfreerdp/codec/h264_ffmpeg.c +++ b/libfreerdp/codec/h264_ffmpeg.c @@ -245,7 +245,8 @@ static int libavcodec_decompress(H264_CONTEXT* h264, const BYTE* pSrcData, return 1; } -static int libavcodec_compress(H264_CONTEXT* h264, BYTE** ppDstData, UINT32* pDstSize) +static int libavcodec_compress(H264_CONTEXT* h264, const BYTE** pSrcYuv, const UINT32* pStride, + BYTE** ppDstData, UINT32* pDstSize) { int status; int gotFrame = 0; @@ -271,12 +272,12 @@ static int libavcodec_compress(H264_CONTEXT* h264, BYTE** ppDstData, UINT32* pDs #if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(52, 92, 100) sys->videoFrame->chroma_location = AVCHROMA_LOC_LEFT; #endif - sys->videoFrame->data[0] = h264->pYUVData[0]; - sys->videoFrame->data[1] = h264->pYUVData[1]; - sys->videoFrame->data[2] = h264->pYUVData[2]; - sys->videoFrame->linesize[0] = h264->iStride[0]; - sys->videoFrame->linesize[1] = h264->iStride[1]; - sys->videoFrame->linesize[2] = h264->iStride[2]; + sys->videoFrame->data[0] = pSrcYuv[0]; + sys->videoFrame->data[1] = pSrcYuv[1]; + sys->videoFrame->data[2] = pSrcYuv[2]; + sys->videoFrame->linesize[0] = pStride[0]; + sys->videoFrame->linesize[1] = pStride[1]; + sys->videoFrame->linesize[2] = pStride[2]; sys->videoFrame->pts++; /* avcodec_encode_video2 is deprecated with libavcodec 57.48.101 */ #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 48, 101) diff --git a/libfreerdp/codec/h264_mf.c b/libfreerdp/codec/h264_mf.c index a8d92a380..34f28801f 100644 --- a/libfreerdp/codec/h264_mf.c +++ b/libfreerdp/codec/h264_mf.c @@ -28,14 +28,14 @@ #include #include +#include "h264.h" + #undef DEFINE_GUID #define INITGUID #include #define TAG FREERDP_TAG("codec") -BOOL avc420_ensure_buffer(H264_CONTEXT* h264, UINT32 stride, UINT32 width, UINT32 height); - DEFINE_GUID(CLSID_CMSH264DecoderMFT, 0x62CE7E72, 0x4C71, 0x4d20, 0xB1, 0x5D, 0x45, 0x28, 0x31, 0xA8, 0x7D, 0x9D); DEFINE_GUID(CLSID_VideoProcessorMFT, 0x88753b26, 0x5b24, 0x49bd, 0xb2, 0xe7, @@ -428,7 +428,7 @@ error: return -1; } -static int mf_compress(H264_CONTEXT* h264, BYTE** ppDstData, UINT32* pDstSize) +static int mf_compress(H264_CONTEXT* h264, const BYTE** ppSrcYuv, const UINT32* pStride, BYTE** ppDstData, UINT32* pDstSize) { H264_CONTEXT_MF* sys = (H264_CONTEXT_MF*) h264->pSystemData; return 1; diff --git a/libfreerdp/codec/h264_openh264.c b/libfreerdp/codec/h264_openh264.c index 451a5bfde..2e35fa4ab 100644 --- a/libfreerdp/codec/h264_openh264.c +++ b/libfreerdp/codec/h264_openh264.c @@ -128,8 +128,8 @@ static int openh264_decompress(H264_CONTEXT* h264, const BYTE* pSrcData, return 1; } -static int openh264_compress(H264_CONTEXT* h264, BYTE** ppDstData, - UINT32* pDstSize) +static int openh264_compress(H264_CONTEXT* h264, const BYTE** pYUVData, const UINT32* iStride, + BYTE** ppDstData, UINT32* pDstSize) { int i, j; int status; @@ -137,8 +137,6 @@ static int openh264_compress(H264_CONTEXT* h264, BYTE** ppDstData, SSourcePicture pic; SBitrateInfo bitrate; H264_CONTEXT_OPENH264* sys; - BYTE** pYUVData = h264->pYUVData; - UINT32* iStride = h264->iStride; sys = &((H264_CONTEXT_OPENH264*) h264->pSystemData)[0]; if (!sys->pEncoder) diff --git a/libfreerdp/codec/h264_x264.c b/libfreerdp/codec/h264_x264.c index 11e7f0eb4..5252e3fa7 100644 --- a/libfreerdp/codec/h264_x264.c +++ b/libfreerdp/codec/h264_x264.c @@ -52,7 +52,7 @@ static int x264_decompress(H264_CONTEXT* h264, BYTE* pSrcData, UINT32 SrcSize) return -1; } -static int x264_compress(H264_CONTEXT* h264, BYTE** ppDstData, UINT32* pDstSize) +static int x264_compress(H264_CONTEXT* h264, const BYTE** ppSrcYuv, const UINT32* pStride, BYTE** ppDstData, UINT32* pDstSize) { //H264_CONTEXT_X264* sys = (H264_CONTEXT_X264*) h264->pSystemData; return -1; diff --git a/server/shadow/shadow_client.c b/server/shadow/shadow_client.c index a81cf2f2c..1f84029c8 100644 --- a/server/shadow/shadow_client.c +++ b/server/shadow/shadow_client.c @@ -709,7 +709,7 @@ static UINT shadow_client_rdpgfx_caps_advertise(RdpgfxServerContext* context, const RDPGFX_CAPSET* currentCaps = &capsAdvertise->capsSets[index]; if (currentCaps->version == RDPGFX_CAPVERSION_81) - { + { RDPGFX_CAPSET caps = *currentCaps; RDPGFX_CAPS_CONFIRM_PDU pdu; pdu.capsSet = ∩︀ @@ -718,8 +718,9 @@ static UINT shadow_client_rdpgfx_caps_advertise(RdpgfxServerContext* context, { flags = pdu.capsSet->flags; settings->GfxAVC444 = FALSE; + settings->GfxAVC444v2 = FALSE; settings->GfxThinClient = (flags & RDPGFX_CAPS_FLAG_THINCLIENT); - settings->GfxSmallCache = (flags & RDPGFX_CAPS_FLAG_SMALL_CACHE); + settings->GfxSmallCache = (flags & RDPGFX_CAPS_FLAG_SMALL_CACHE); #ifndef WITH_GFX_H264 settings->GfxH264 = FALSE; pdu.capsSet->flags &= ~RDPGFX_CAPS_FLAG_AVC420_ENABLED; @@ -811,11 +812,12 @@ static BOOL shadow_client_send_surface_gfx(rdpShadowClient* client, cmd.data = NULL; cmd.extra = NULL; - if (settings->GfxAVC444) + if (settings->GfxAVC444 || settings->GfxAVC444v2) { RDPGFX_AVC444_BITMAP_STREAM avc444; RECTANGLE_16 regionRect; RDPGFX_H264_QUANT_QUALITY quantQualityVal; + BYTE version = settings->GfxAVC444v2 ? 2 : 1; if (shadow_encoder_prepare(encoder, FREERDP_CODEC_AVC444) < 0) { @@ -823,9 +825,10 @@ static BOOL shadow_client_send_surface_gfx(rdpShadowClient* client, return FALSE; } - if (avc420_compress(encoder->h264, pSrcData, cmd.format, nSrcStep, - nWidth, nHeight, &avc444.bitstream[0].data, - &avc444.bitstream[0].length) < 0) + 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) { WLog_ERR(TAG, "avc420_compress failed for avc444"); return FALSE; @@ -842,12 +845,12 @@ static BOOL shadow_client_send_surface_gfx(rdpShadowClient* client, avc444.bitstream[0].meta.numRegionRects = 1; avc444.bitstream[0].meta.regionRects = ®ionRect; avc444.bitstream[0].meta.quantQualityVals = &quantQualityVal; - avc444.LC = 1; + 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 = RDPGFX_CODECID_AVC444; + cmd.codecId = settings->GfxAVC444v2 ? RDPGFX_CODECID_AVC444v2 : RDPGFX_CODECID_AVC444; cmd.extra = (void*)&avc444; - IFCALLRET(client->rdpgfx->SurfaceFrameCommand, error, client->rdpgfx, &cmd, &cmdstart, &cmdend); @@ -870,7 +873,7 @@ static BOOL shadow_client_send_surface_gfx(rdpShadowClient* client, } if (avc420_compress(encoder->h264, pSrcData, cmd.format, nSrcStep, - nWidth, nHeight, &avc420.data, &avc420.length) < 0) + nWidth, nHeight, &avc420.data, &avc420.length) < 0) { WLog_ERR(TAG, "avc420_compress failed"); return FALSE;