Skip to content

Commit

Permalink
Fix H264 in multi monitor case
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
hardening committed May 2, 2017
1 parent 8569102 commit d170c10
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 32 deletions.
54 changes: 36 additions & 18 deletions client/X11/xf_gfx.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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))
Expand All @@ -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;
}

/**
Expand Down
1 change: 1 addition & 0 deletions include/freerdp/gdi/gfx.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ struct gdi_gfx_surface
{
UINT16 surfaceId;
rdpCodecs* codecs;
H264_CONTEXT *h264;
UINT32 width;
UINT32 height;
BYTE* data;
Expand Down
41 changes: 27 additions & 14 deletions libfreerdp/gdi/gfx.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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)
Expand All @@ -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,
Expand All @@ -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)
Expand Down Expand Up @@ -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);
Expand All @@ -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;
}
Expand Down

0 comments on commit d170c10

Please sign in to comment.