From: David Fort Date: Mon, 1 May 2017 20:39:52 +0000 (+0200) Subject: Fix H264 in multi monitor case X-Git-Tag: 2.0.0-rc0~39^2~1 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=d170c10ee6000668303e82fb00d4697e4601ec7d;p=platform%2Fupstream%2Ffreerdp.git 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. --- diff --git a/client/X11/xf_gfx.c b/client/X11/xf_gfx.c index 4f89dfb..a6a85b5 100644 --- a/client/X11/xf_gfx.c +++ b/client/X11/xf_gfx.c @@ -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; } /** diff --git a/include/freerdp/gdi/gfx.h b/include/freerdp/gdi/gfx.h index a03490e..24de3e0 100644 --- a/include/freerdp/gdi/gfx.h +++ b/include/freerdp/gdi/gfx.h @@ -27,6 +27,7 @@ struct gdi_gfx_surface { UINT16 surfaceId; rdpCodecs* codecs; + H264_CONTEXT *h264; UINT32 width; UINT32 height; BYTE* data; diff --git a/libfreerdp/gdi/gfx.c b/libfreerdp/gdi/gfx.c index be30280..16a7290 100644 --- a/libfreerdp/gdi/gfx.c +++ b/libfreerdp/gdi/gfx.c @@ -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; }