mirror of
https://github.com/morgan9e/FreeRDP
synced 2026-04-14 08:24:16 +09:00
Fix H264 in multi monitor case
The H264 context is surface specific, so in multi-monitor (with multiple surfaces) the decoding was failing. This patch fixes that by introducing a surface specific h264 context.
This commit is contained in:
@@ -210,21 +210,21 @@ UINT32 x11_pad_scanline(UINT32 scanline, UINT32 inPad)
|
||||
static UINT xf_CreateSurface(RdpgfxClientContext* context,
|
||||
const RDPGFX_CREATE_SURFACE_PDU* createSurface)
|
||||
{
|
||||
UINT ret = CHANNEL_RC_NO_MEMORY;
|
||||
size_t size;
|
||||
xfGfxSurface* surface;
|
||||
rdpGdi* gdi = (rdpGdi*)context->custom;
|
||||
xfContext* xfc = (xfContext*) gdi->context;
|
||||
surface = (xfGfxSurface*) calloc(1, sizeof(xfGfxSurface));
|
||||
|
||||
surface = (xfGfxSurface *) calloc(1, sizeof(xfGfxSurface));
|
||||
if (!surface)
|
||||
return CHANNEL_RC_NO_MEMORY;
|
||||
|
||||
surface->gdi.codecs = gdi->context->codecs;
|
||||
|
||||
if (!surface->gdi.codecs)
|
||||
{
|
||||
free(surface);
|
||||
return CHANNEL_RC_NO_MEMORY;
|
||||
WLog_ERR(TAG, "%s: global GDI codecs aren't set", __FUNCTION__);
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
surface->gdi.surfaceId = createSurface->surfaceId;
|
||||
@@ -242,22 +242,21 @@ static UINT xf_CreateSurface(RdpgfxClientContext* context,
|
||||
break;
|
||||
|
||||
default:
|
||||
free(surface);
|
||||
return ERROR_INTERNAL_ERROR;
|
||||
WLog_ERR(TAG, "%s: unknown pixelFormat 0x%"PRIx32"", __FUNCTION__, createSurface->pixelFormat);
|
||||
ret = ERROR_INTERNAL_ERROR;
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
surface->gdi.scanline = surface->gdi.width * GetBytesPerPixel(
|
||||
surface->gdi.format);
|
||||
surface->gdi.scanline = surface->gdi.width * GetBytesPerPixel(surface->gdi.format);
|
||||
surface->gdi.scanline = x11_pad_scanline(surface->gdi.scanline, xfc->scanline_pad);
|
||||
size = surface->gdi.scanline * surface->gdi.height;
|
||||
surface->gdi.data = (BYTE*) _aligned_malloc(size, 16);
|
||||
|
||||
surface->gdi.data = (BYTE*)_aligned_malloc(size, 16);
|
||||
if (!surface->gdi.data)
|
||||
{
|
||||
free(surface);
|
||||
return CHANNEL_RC_NO_MEMORY;
|
||||
WLog_ERR(TAG, "%s: unable to allocate GDI data", __FUNCTION__);
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
ZeroMemory(surface->gdi.data, size);
|
||||
|
||||
if (AreColorFormatsEqualNoAlpha(gdi->dstFormat, surface->gdi.format))
|
||||
@@ -273,26 +272,45 @@ static UINT xf_CreateSurface(RdpgfxClientContext* context,
|
||||
surface->stageScanline = width * bytes;
|
||||
surface->stageScanline = x11_pad_scanline(surface->stageScanline, xfc->scanline_pad);
|
||||
size = surface->stageScanline * surface->gdi.height;
|
||||
surface->stage = (BYTE*) _aligned_malloc(size, 16);
|
||||
|
||||
surface->stage = (BYTE*) _aligned_malloc(size, 16);
|
||||
if (!surface->stage)
|
||||
{
|
||||
_aligned_free(surface->gdi.data);
|
||||
free(surface);
|
||||
return CHANNEL_RC_NO_MEMORY;
|
||||
WLog_ERR(TAG, "%s: unable to allocate stage buffer", __FUNCTION__);
|
||||
goto out_free_gdidata;
|
||||
}
|
||||
|
||||
ZeroMemory(surface->stage, size);
|
||||
|
||||
surface->image = XCreateImage(xfc->display, xfc->visual, xfc->depth,
|
||||
ZPixmap, 0, (char*) surface->stage,
|
||||
surface->gdi.width, surface->gdi.height,
|
||||
xfc->scanline_pad, surface->stageScanline);
|
||||
}
|
||||
|
||||
if (!surface->image)
|
||||
{
|
||||
WLog_ERR(TAG, "%s: an error occurred when creating the XImage", __FUNCTION__);
|
||||
goto error_surface_image;
|
||||
}
|
||||
|
||||
surface->gdi.outputMapped = FALSE;
|
||||
region16_init(&surface->gdi.invalidRegion);
|
||||
context->SetSurfaceData(context, surface->gdi.surfaceId, (void*) surface);
|
||||
if (context->SetSurfaceData(context, surface->gdi.surfaceId, (void*) surface) < 0)
|
||||
{
|
||||
WLog_ERR(TAG, "%s: an error occurred during SetSurfaceData", __FUNCTION__);
|
||||
goto error_set_surface_data;
|
||||
}
|
||||
return CHANNEL_RC_OK;
|
||||
|
||||
error_set_surface_data:
|
||||
XFree(surface->image);
|
||||
error_surface_image:
|
||||
_aligned_free(surface->stage);
|
||||
out_free_gdidata:
|
||||
_aligned_free(surface->gdi.data);
|
||||
out_free:
|
||||
free(surface);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -27,6 +27,7 @@ struct gdi_gfx_surface
|
||||
{
|
||||
UINT16 surfaceId;
|
||||
rdpCodecs* codecs;
|
||||
H264_CONTEXT *h264;
|
||||
UINT32 width;
|
||||
UINT32 height;
|
||||
BYTE* data;
|
||||
|
||||
@@ -402,14 +402,22 @@ static UINT gdi_SurfaceCommand_AVC420(rdpGdi* gdi,
|
||||
return ERROR_NOT_FOUND;
|
||||
}
|
||||
|
||||
bs = (RDPGFX_AVC420_BITMAP_STREAM*) cmd->extra;
|
||||
if (!surface->h264)
|
||||
{
|
||||
surface->h264 = h264_context_new(FALSE);
|
||||
if (!surface->h264)
|
||||
{
|
||||
WLog_ERR(TAG, "%s: unable to create h264 context", __FUNCTION__);
|
||||
return ERROR_NOT_ENOUGH_MEMORY;
|
||||
}
|
||||
}
|
||||
|
||||
bs = (RDPGFX_AVC420_BITMAP_STREAM*) cmd->extra;
|
||||
if (!bs)
|
||||
return ERROR_INTERNAL_ERROR;
|
||||
|
||||
meta = &(bs->meta);
|
||||
rc = avc420_decompress(surface->codecs->h264, bs->data, bs->length,
|
||||
surface->data, surface->format,
|
||||
rc = avc420_decompress(surface->h264, bs->data, bs->length, surface->data, surface->format,
|
||||
surface->scanline, surface->width,
|
||||
surface->height, meta->regionRects,
|
||||
meta->numRegionRects);
|
||||
@@ -462,6 +470,16 @@ static UINT gdi_SurfaceCommand_AVC444(rdpGdi* gdi, RdpgfxClientContext* context,
|
||||
return ERROR_NOT_FOUND;
|
||||
}
|
||||
|
||||
if (!surface->h264)
|
||||
{
|
||||
surface->h264 = h264_context_new(FALSE);
|
||||
if (!surface->h264)
|
||||
{
|
||||
WLog_ERR(TAG, "%s: unable to create h264 context", __FUNCTION__);
|
||||
return ERROR_NOT_ENOUGH_MEMORY;
|
||||
}
|
||||
}
|
||||
|
||||
bs = (RDPGFX_AVC444_BITMAP_STREAM*) cmd->extra;
|
||||
|
||||
if (!bs)
|
||||
@@ -471,7 +489,7 @@ static UINT gdi_SurfaceCommand_AVC444(rdpGdi* gdi, RdpgfxClientContext* context,
|
||||
avc2 = &bs->bitstream[1];
|
||||
meta1 = &avc1->meta;
|
||||
meta2 = &avc2->meta;
|
||||
rc = avc444_decompress(surface->codecs->h264, bs->LC,
|
||||
rc = avc444_decompress(surface->h264, bs->LC,
|
||||
meta1->regionRects, meta1->numRegionRects,
|
||||
avc1->data, avc1->length,
|
||||
meta2->regionRects, meta2->numRegionRects,
|
||||
@@ -488,16 +506,12 @@ static UINT gdi_SurfaceCommand_AVC444(rdpGdi* gdi, RdpgfxClientContext* context,
|
||||
|
||||
for (i = 0; i < meta1->numRegionRects; i++)
|
||||
{
|
||||
region16_union_rect(&(surface->invalidRegion),
|
||||
&(surface->invalidRegion),
|
||||
&(meta1->regionRects[i]));
|
||||
region16_union_rect(&(surface->invalidRegion), &(surface->invalidRegion), &(meta1->regionRects[i]));
|
||||
}
|
||||
|
||||
for (i = 0; i < meta2->numRegionRects; i++)
|
||||
{
|
||||
region16_union_rect(&(surface->invalidRegion),
|
||||
&(surface->invalidRegion),
|
||||
&(meta2->regionRects[i]));
|
||||
region16_union_rect(&(surface->invalidRegion), &(surface->invalidRegion), &(meta2->regionRects[i]));
|
||||
}
|
||||
|
||||
if (!gdi->inGfxFrame)
|
||||
@@ -758,11 +772,11 @@ static UINT gdi_DeleteSurface(RdpgfxClientContext* context,
|
||||
{
|
||||
rdpCodecs* codecs = NULL;
|
||||
gdiGfxSurface* surface = NULL;
|
||||
surface = (gdiGfxSurface*) context->GetSurfaceData(context,
|
||||
deleteSurface->surfaceId);
|
||||
surface = (gdiGfxSurface*) context->GetSurfaceData(context, deleteSurface->surfaceId);
|
||||
|
||||
if (surface)
|
||||
{
|
||||
h264_context_free(surface->h264);
|
||||
region16_uninit(&surface->invalidRegion);
|
||||
codecs = surface->codecs;
|
||||
_aligned_free(surface->data);
|
||||
@@ -772,8 +786,7 @@ static UINT gdi_DeleteSurface(RdpgfxClientContext* context,
|
||||
context->SetSurfaceData(context, deleteSurface->surfaceId, NULL);
|
||||
|
||||
if (codecs && codecs->progressive)
|
||||
progressive_delete_surface_context(codecs->progressive,
|
||||
deleteSurface->surfaceId);
|
||||
progressive_delete_surface_context(codecs->progressive, deleteSurface->surfaceId);
|
||||
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user