Added AVC444 chroma support to shadow server.

This commit is contained in:
Armin Novak
2018-01-31 15:08:11 +01:00
parent a90be56099
commit 3b70d1178b
10 changed files with 143 additions and 47 deletions

View File

@@ -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;

View File

@@ -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);

View File

@@ -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

View File

@@ -32,8 +32,12 @@
#include <freerdp/codec/h264.h>
#include <freerdp/log.h>
#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);
}
}

31
libfreerdp/codec/h264.h Normal file
View File

@@ -0,0 +1,31 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* RemoteFX Codec Library - Decode
*
* Copyright 2018 Armin Novak <anovak@thincast.com>
* 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 <freerdp/api.h>
#include <freerdp/codec/h264.h>
FREERDP_LOCAL BOOL avc420_ensure_buffer(H264_CONTEXT* h264,
UINT32 stride, UINT32 width, UINT32 height);
#endif /* FREERDP_LIB_CODEC_H264_H */

View File

@@ -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)

View File

@@ -28,14 +28,14 @@
#include <wmcodecdsp.h>
#include <mftransform.h>
#include "h264.h"
#undef DEFINE_GUID
#define INITGUID
#include <initguid.h>
#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;

View File

@@ -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)

View File

@@ -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;

View File

@@ -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 = &caps;
@@ -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 = &regionRect;
avc444.bitstream[0].meta.quantQualityVals = &quantQualityVal;
avc444.LC = 1;
avc444.bitstream[1].meta.numRegionRects = 1;
avc444.bitstream[1].meta.regionRects = &regionRect;
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;