From d1c764b374a4dd939573fb298f87d3caff526c7a Mon Sep 17 00:00:00 2001 From: Mike McDonald Date: Tue, 3 Jun 2014 06:58:49 -0400 Subject: [PATCH 1/3] Revert "Modified SCardConnect/SCardDisconnect logic to prevent more than one card from being connected to a context. Trying to connect more than once to a context without doing a disconnect can cause a deadlock in the pcsclite daemon (pcscd)." This reverts commit ed8ea297e790fd0e26e1a04148a3e6de2ea46dca. --- winpr/libwinpr/smartcard/smartcard_pcsc.c | 25 ----------------------- 1 file changed, 25 deletions(-) diff --git a/winpr/libwinpr/smartcard/smartcard_pcsc.c b/winpr/libwinpr/smartcard/smartcard_pcsc.c index 3553db8e8..5ba47a958 100644 --- a/winpr/libwinpr/smartcard/smartcard_pcsc.c +++ b/winpr/libwinpr/smartcard/smartcard_pcsc.c @@ -386,22 +386,9 @@ SCARDCONTEXT PCSC_GetCardContextFromHandle(SCARDHANDLE hCard) return pCard->hContext; } -BOOL PCSC_IsCardHandleConnected(SCARDCONTEXT hContext) -{ - PCSC_SCARDCONTEXT* pContext; - - pContext = PCSC_GetCardContextData(hContext); - - if (!pContext) - return FALSE; - - return pContext->hCard ? TRUE : FALSE; -} - PCSC_SCARDHANDLE* PCSC_ConnectCardHandle(SCARDCONTEXT hContext, SCARDHANDLE hCard) { PCSC_SCARDHANDLE* pCard; - PCSC_SCARDCONTEXT* pContext; pCard = (PCSC_SCARDHANDLE*) calloc(1, sizeof(PCSC_SCARDHANDLE)); @@ -412,10 +399,6 @@ PCSC_SCARDHANDLE* PCSC_ConnectCardHandle(SCARDCONTEXT hContext, SCARDHANDLE hCar InitializeCriticalSectionAndSpinCount(&(pCard->lock), 4000); - pContext = PCSC_GetCardContextData(hContext); - - pContext->hCard = hCard; - if (!g_CardHandles) g_CardHandles = ListDictionary_New(TRUE); @@ -427,7 +410,6 @@ PCSC_SCARDHANDLE* PCSC_ConnectCardHandle(SCARDCONTEXT hContext, SCARDHANDLE hCar void PCSC_DisconnectCardHandle(SCARDHANDLE hCard) { PCSC_SCARDHANDLE* pCard; - PCSC_SCARDCONTEXT* pContext; pCard = PCSC_GetCardHandleData(hCard); @@ -436,10 +418,6 @@ void PCSC_DisconnectCardHandle(SCARDHANDLE hCard) DeleteCriticalSection(&(pCard->lock)); - pContext = PCSC_GetCardContextData(pCard->hContext); - - pContext->hCard = 0; - free(pCard); if (!g_CardHandles) @@ -1619,9 +1597,6 @@ WINSCARDAPI LONG WINAPI PCSC_SCardConnect_Internal(SCARDCONTEXT hContext, if (!g_PCSC.pfnSCardConnect) return SCARD_E_NO_SERVICE; - if (PCSC_IsCardHandleConnected(hContext)) - return SCARD_E_SHARING_VIOLATION; - szReaderPCSC = PCSC_GetReaderNameFromAlias((char*) szReader); if (!szReaderPCSC) From 4881ca6bc1fe92192d8e3ccd688227b0eb0357a7 Mon Sep 17 00:00:00 2001 From: Mike McDonald Date: Tue, 3 Jun 2014 07:25:21 -0400 Subject: [PATCH 2/3] Fixed merge issue with smartcard_pcsc.c --- winpr/libwinpr/smartcard/smartcard_pcsc.c | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/winpr/libwinpr/smartcard/smartcard_pcsc.c b/winpr/libwinpr/smartcard/smartcard_pcsc.c index 3b4266d59..75cc5dd36 100644 --- a/winpr/libwinpr/smartcard/smartcard_pcsc.c +++ b/winpr/libwinpr/smartcard/smartcard_pcsc.c @@ -420,11 +420,6 @@ SCARDCONTEXT PCSC_GetCardContextFromHandle(SCARDHANDLE hCard) return pCard->hPrivateContext; } -<<<<<<< HEAD -PCSC_SCARDHANDLE* PCSC_ConnectCardHandle(SCARDCONTEXT hContext, SCARDHANDLE hCard) -{ - PCSC_SCARDHANDLE* pCard; -======= PCSC_SCARDHANDLE* PCSC_ConnectCardHandle(SCARDCONTEXT hSharedContext, SCARDCONTEXT hPrivateContext, SCARDHANDLE hCard) { PCSC_SCARDHANDLE* pCard; @@ -437,7 +432,6 @@ PCSC_SCARDHANDLE* PCSC_ConnectCardHandle(SCARDCONTEXT hSharedContext, SCARDCONTE printf("PCSC_ConnectCardHandle: null pContext!\n"); return NULL; } ->>>>>>> 659f80e172885924c9fb899155c7b76cc8974475 pCard = (PCSC_SCARDHANDLE*) calloc(1, sizeof(PCSC_SCARDHANDLE)); @@ -449,11 +443,8 @@ PCSC_SCARDHANDLE* PCSC_ConnectCardHandle(SCARDCONTEXT hSharedContext, SCARDCONTE InitializeCriticalSectionAndSpinCount(&(pCard->lock), 4000); -<<<<<<< HEAD -======= pContext->dwCardHandleCount++; ->>>>>>> 659f80e172885924c9fb899155c7b76cc8974475 if (!g_CardHandles) g_CardHandles = ListDictionary_New(TRUE); @@ -465,6 +456,7 @@ PCSC_SCARDHANDLE* PCSC_ConnectCardHandle(SCARDCONTEXT hSharedContext, SCARDCONTE void PCSC_DisconnectCardHandle(SCARDHANDLE hCard) { PCSC_SCARDHANDLE* pCard; + PCSC_SCARDCONTEXT* pContext; pCard = PCSC_GetCardHandleData(hCard); @@ -473,13 +465,10 @@ void PCSC_DisconnectCardHandle(SCARDHANDLE hCard) DeleteCriticalSection(&(pCard->lock)); -<<<<<<< HEAD -======= pContext = PCSC_GetCardContextData(pCard->hSharedContext); PCSC_SCardReleaseContext_Internal(pCard->hPrivateContext); ->>>>>>> 659f80e172885924c9fb899155c7b76cc8974475 free(pCard); if (!g_CardHandles) @@ -1687,14 +1676,11 @@ WINSCARDAPI LONG WINAPI PCSC_SCardConnect_Internal(SCARDCONTEXT hContext, if (!g_PCSC.pfnSCardConnect) return SCARD_E_NO_SERVICE; -<<<<<<< HEAD -======= status = PCSC_SCardEstablishContext_Internal(SCARD_SCOPE_SYSTEM, NULL, NULL, &hPrivateContext); if (status != SCARD_S_SUCCESS) return status; ->>>>>>> 659f80e172885924c9fb899155c7b76cc8974475 szReaderPCSC = PCSC_GetReaderNameFromAlias((char*) szReader); if (!szReaderPCSC) From 4d3d78c48799dbce9f1d6aa827aa5a884992476f Mon Sep 17 00:00:00 2001 From: Mike McDonald Date: Tue, 1 Jul 2014 23:28:09 -0400 Subject: [PATCH 3/3] Initial implementation of H.264 decoder for MS-RDPEGFX --- CMakeLists.txt | 5 + channels/rdpgfx/client/rdpgfx_main.c | 7 +- client/X11/xf_gfx.c | 166 +++++++++++++++- client/X11/xfreerdp.h | 2 + cmake/FindOpenH264.cmake | 31 +++ include/freerdp/codec/h264.h | 60 ++++++ libfreerdp/codec/CMakeLists.txt | 15 +- libfreerdp/codec/h264.c | 281 +++++++++++++++++++++++++++ 8 files changed, 557 insertions(+), 10 deletions(-) create mode 100644 cmake/FindOpenH264.cmake create mode 100644 include/freerdp/codec/h264.h create mode 100644 libfreerdp/codec/h264.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 07653d65c..20bda93cf 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -433,6 +433,10 @@ set(JPEG_FEATURE_TYPE "OPTIONAL") set(JPEG_FEATURE_PURPOSE "codec") set(JPEG_FEATURE_DESCRIPTION "use JPEG library") +set(OPENH264_FEATURE_TYPE "OPTIONAL") +set(OPENH264_FEATURE_PURPOSE "codec") +set(OPENH264_FEATURE_DESCRIPTION "use OpenH264 library") + set(GSM_FEATURE_TYPE "OPTIONAL") set(GSM_FEATURE_PURPOSE "codec") set(GSM_FEATURE_DESCRIPTION "GSM audio codec library") @@ -504,6 +508,7 @@ find_feature(GStreamer_0_10 ${GSTREAMER_0_10_FEATURE_TYPE} ${GSTREAMER_0_10_FEAT find_feature(GStreamer_1_0 ${GSTREAMER_1_0_FEATURE_TYPE} ${GSTREAMER_1_0_FEATURE_PURPOSE} ${GSTREAMER_1_0_FEATURE_DESCRIPTION}) find_feature(JPEG ${JPEG_FEATURE_TYPE} ${JPEG_FEATURE_PURPOSE} ${JPEG_FEATURE_DESCRIPTION}) +find_feature(OpenH264 ${OPENH264_FEATURE_TYPE} ${OPENH264_FEATURE_PURPOSE} ${OPENH264_FEATURE_DESCRIPTION}) find_feature(GSM ${GSM_FEATURE_TYPE} ${GSM_FEATURE_PURPOSE} ${GSM_FEATURE_DESCRIPTION}) if(TARGET_ARCH MATCHES "x86|x64") diff --git a/channels/rdpgfx/client/rdpgfx_main.c b/channels/rdpgfx/client/rdpgfx_main.c index 032b51b81..575235c0e 100644 --- a/channels/rdpgfx/client/rdpgfx_main.c +++ b/channels/rdpgfx/client/rdpgfx_main.c @@ -58,14 +58,19 @@ int rdpgfx_send_caps_advertise_pdu(RDPGFX_CHANNEL_CALLBACK* callback) gfx->ThinClient = TRUE; gfx->SmallCache = FALSE; + +#ifdef WITH_OPENH264 + gfx->H264 = TRUE; +#else gfx->H264 = FALSE; +#endif gfx->MaxCacheSlot = (gfx->ThinClient) ? 4096 : 25600; header.flags = 0; header.cmdId = RDPGFX_CMDID_CAPSADVERTISE; - pdu.capsSetCount = 1; + pdu.capsSetCount = 2; pdu.capsSets = (RDPGFX_CAPSET*) capsSets; capsSet = &capsSets[0]; diff --git a/client/X11/xf_gfx.c b/client/X11/xf_gfx.c index 01ec06081..c04b1319e 100644 --- a/client/X11/xf_gfx.c +++ b/client/X11/xf_gfx.c @@ -51,8 +51,22 @@ int xf_ResetGraphics(RdpgfxClientContext* context, RDPGFX_RESET_GRAPHICS_PDU* re xfc->nsc->height = resetGraphics->height; nsc_context_set_pixel_format(xfc->nsc, RDP_PIXEL_FORMAT_B8G8R8A8); + if (xfc->clear) + { + clear_context_free(xfc->clear); + xfc->clear = NULL; + } + xfc->clear = clear_context_new(FALSE); + if (xfc->h264) + { + h264_context_free(xfc->h264); + xfc->h264 = NULL; + } + + xfc->h264 = h264_context_new(FALSE); + region16_init(&(xfc->invalidRegion)); xfc->graphicsReset = TRUE; @@ -267,10 +281,16 @@ int xf_SurfaceCommand_ClearCodec(xfContext* xfc, RdpgfxClientContext* context, R DstData = surface->data; +#if 0 status = clear_decompress(NULL, cmd->data, cmd->length, &DstData, PIXEL_FORMAT_XRGB32, surface->scanline, cmd->left, cmd->top, cmd->width, cmd->height); +#else + status = -1; +#endif -#if 0 + printf("xf_SurfaceCommand_ClearCodec: status: %d\n", status); + +#if 1 /* fill with pink for now to distinguish from the rest */ freerdp_image_fill(surface->data, PIXEL_FORMAT_XRGB32, surface->scanline, @@ -320,6 +340,142 @@ int xf_SurfaceCommand_Planar(xfContext* xfc, RdpgfxClientContext* context, RDPGF return 1; } +int xf_SurfaceCommand_H264(xfContext* xfc, RdpgfxClientContext* context, RDPGFX_SURFACE_COMMAND* cmd) +{ + int status; + BYTE* DstData = NULL; + xfGfxSurface* surface; + RECTANGLE_16 invalidRect; + + surface = (xfGfxSurface*) context->GetSurfaceData(context, cmd->surfaceId); + + if (!surface) + return -1; + + DstData = surface->data; + +#if 1 + status = h264_decompress(xfc->h264, cmd->data, cmd->length, &DstData, + PIXEL_FORMAT_XRGB32, surface->scanline, cmd->left, cmd->top, cmd->width, cmd->height); +#else + status = -1; +#endif + + printf("xf_SurfaceCommand_H264: status: %d\n", status); + +#if 0 + /* fill with red for now to distinguish from the rest */ + + freerdp_image_fill(surface->data, PIXEL_FORMAT_XRGB32, surface->scanline, + cmd->left, cmd->top, cmd->width, cmd->height, 0xFF0000); +#endif + + invalidRect.left = cmd->left; + invalidRect.top = cmd->top; + invalidRect.right = cmd->right; + invalidRect.bottom = cmd->bottom; + + region16_union_rect(&(xfc->invalidRegion), &(xfc->invalidRegion), &invalidRect); + + if (!xfc->inGfxFrame) + xf_OutputUpdate(xfc); + + return 1; +} + +int xf_SurfaceCommand_Alpha(xfContext* xfc, RdpgfxClientContext* context, RDPGFX_SURFACE_COMMAND* cmd) +{ + int status = 0; + xfGfxSurface* surface; + RECTANGLE_16 invalidRect; + + surface = (xfGfxSurface*) context->GetSurfaceData(context, cmd->surfaceId); + + if (!surface) + return -1; + + printf("xf_SurfaceCommand_Alpha: status: %d\n", status); + + /* fill with green for now to distinguish from the rest */ + + freerdp_image_fill(surface->data, PIXEL_FORMAT_XRGB32, surface->scanline, + cmd->left, cmd->top, cmd->width, cmd->height, 0x00FF00); + + invalidRect.left = cmd->left; + invalidRect.top = cmd->top; + invalidRect.right = cmd->right; + invalidRect.bottom = cmd->bottom; + + region16_union_rect(&(xfc->invalidRegion), &(xfc->invalidRegion), &invalidRect); + + if (!xfc->inGfxFrame) + xf_OutputUpdate(xfc); + + return 1; +} + +int xf_SurfaceCommand_Progressive(xfContext* xfc, RdpgfxClientContext* context, RDPGFX_SURFACE_COMMAND* cmd) +{ + int status = 0; + xfGfxSurface* surface; + RECTANGLE_16 invalidRect; + + surface = (xfGfxSurface*) context->GetSurfaceData(context, cmd->surfaceId); + + if (!surface) + return -1; + + printf("xf_SurfaceCommand_Progressive: status: %d\n", status); + + /* fill with blue for now to distinguish from the rest */ + + freerdp_image_fill(surface->data, PIXEL_FORMAT_XRGB32, surface->scanline, + cmd->left, cmd->top, cmd->width, cmd->height, 0x0000FF); + + invalidRect.left = cmd->left; + invalidRect.top = cmd->top; + invalidRect.right = cmd->right; + invalidRect.bottom = cmd->bottom; + + region16_union_rect(&(xfc->invalidRegion), &(xfc->invalidRegion), &invalidRect); + + if (!xfc->inGfxFrame) + xf_OutputUpdate(xfc); + + return 1; +} + +int xf_SurfaceCommand_ProgressiveV2(xfContext* xfc, RdpgfxClientContext* context, RDPGFX_SURFACE_COMMAND* cmd) +{ + int status = 0; + xfGfxSurface* surface; + RECTANGLE_16 invalidRect; + + surface = (xfGfxSurface*) context->GetSurfaceData(context, cmd->surfaceId); + + if (!surface) + return -1; + + printf("xf_SurfaceCommand_ProgressiveV2: status: %d\n", status); + + /* fill with white for now to distinguish from the rest */ + + freerdp_image_fill(surface->data, PIXEL_FORMAT_XRGB32, surface->scanline, + cmd->left, cmd->top, cmd->width, cmd->height, 0xFFFFFF); + + invalidRect.left = cmd->left; + invalidRect.top = cmd->top; + invalidRect.right = cmd->right; + invalidRect.bottom = cmd->bottom; + + region16_union_rect(&(xfc->invalidRegion), &(xfc->invalidRegion), &invalidRect); + + if (!xfc->inGfxFrame) + xf_OutputUpdate(xfc); + + return 1; +} + int xf_SurfaceCommand(RdpgfxClientContext* context, RDPGFX_SURFACE_COMMAND* cmd) { int status = 1; @@ -344,19 +500,19 @@ int xf_SurfaceCommand(RdpgfxClientContext* context, RDPGFX_SURFACE_COMMAND* cmd) break; case RDPGFX_CODECID_H264: - printf("xf_SurfaceCommand_H264\n"); + status = xf_SurfaceCommand_H264(xfc, context, cmd); break; case RDPGFX_CODECID_ALPHA: - printf("xf_SurfaceCommand_Alpha\n"); + status = xf_SurfaceCommand_Alpha(xfc, context, cmd); break; case RDPGFX_CODECID_CAPROGRESSIVE: - printf("xf_SurfaceCommand_Progressive\n"); + status = xf_SurfaceCommand_Progressive(xfc, context, cmd); break; case RDPGFX_CODECID_CAPROGRESSIVE_V2: - printf("xf_SurfaceCommand_ProgressiveV2\n"); + status = xf_SurfaceCommand_ProgressiveV2(xfc, context, cmd); break; } diff --git a/client/X11/xfreerdp.h b/client/X11/xfreerdp.h index a1e6ebf16..16d79526d 100644 --- a/client/X11/xfreerdp.h +++ b/client/X11/xfreerdp.h @@ -34,6 +34,7 @@ typedef struct xf_context xfContext; #include #include #include +#include #include struct xf_WorkArea @@ -152,6 +153,7 @@ struct xf_context RFX_CONTEXT* rfx; NSC_CONTEXT* nsc; CLEAR_CONTEXT* clear; + H264_CONTEXT* h264; void* xv_context; void* clipboard_context; diff --git a/cmake/FindOpenH264.cmake b/cmake/FindOpenH264.cmake new file mode 100644 index 000000000..2e06e34d1 --- /dev/null +++ b/cmake/FindOpenH264.cmake @@ -0,0 +1,31 @@ +# - Try to find the OpenH264 library +# Once done this will define +# +# OPENH264_FOUND - system has OpenH264 +# OPENH264_INCLUDE_DIR - the OpenH264 include directory +# OPENH264_LIBRARIES - libopenh264 library + +if (OPENH264_INCLUDE_DIR AND OPENH264_LIBRARY) + set(OPENH264_FIND_QUIETLY TRUE) +endif (OPENH264_INCLUDE_DIR AND OPENH264_LIBRARY) + +find_path(OPENH264_INCLUDE_DIR NAMES wels/codec_api.h wels/codec_app_def.h wels/codec_def.h) +find_library(OPENH264_LIBRARY openh264) + +if (OPENH264_INCLUDE_DIR AND OPENH264_LIBRARY) + set(OPENH264_FOUND TRUE) + set(OPENH264_LIBRARIES ${OPENH264_LIBRARY}) +endif (OPENH264_INCLUDE_DIR AND OPENH264_LIBRARY) + +if (OPENH264_FOUND) + if (NOT OPENH264_FIND_QUIETLY) + message(STATUS "Found OpenH264: ${OPENH264_LIBRARIES}") + endif (NOT OPENH264_FIND_QUIETLY) +else (OPENH264_FOUND) + if (OPENH264_FIND_REQUIRED) + message(FATAL_ERROR "OpenH264 was not found") + endif(OPENH264_FIND_REQUIRED) +endif (OPENH264_FOUND) + +mark_as_advanced(OPENH264_INCLUDE_DIR OPENH264_LIBRARY) + diff --git a/include/freerdp/codec/h264.h b/include/freerdp/codec/h264.h new file mode 100644 index 000000000..f7f6a1377 --- /dev/null +++ b/include/freerdp/codec/h264.h @@ -0,0 +1,60 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * H.264 Bitmap Compression + * + * Copyright 2014 Mike McDonald + * + * 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_CODEC_H264_H +#define FREERDP_CODEC_H264_H + +#include +#include + +#ifdef WITH_OPENH264 +#include "wels/codec_def.h" +#include "wels/codec_api.h" +#endif + +struct _H264_CONTEXT +{ + BOOL Compressor; + +#ifdef WITH_OPENH264 + ISVCDecoder* pDecoder; +#endif +}; +typedef struct _H264_CONTEXT H264_CONTEXT; + +#ifdef __cplusplus +extern "C" { +#endif + +FREERDP_API int h264_compress(H264_CONTEXT* h264, BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstData, UINT32* pDstSize); + +FREERDP_API int h264_decompress(H264_CONTEXT* h264, BYTE* pSrcData, UINT32 SrcSize, + BYTE** ppDstData, DWORD DstFormat, int nDstStep, int nXDst, int nYDst, int nWidth, int nHeight); + +FREERDP_API void h264_context_reset(H264_CONTEXT* h264); + +FREERDP_API H264_CONTEXT* h264_context_new(BOOL Compressor); +FREERDP_API void h264_context_free(H264_CONTEXT* h264); + +#ifdef __cplusplus +} +#endif + +#endif /* FREERDP_CODEC_H264_H */ + diff --git a/libfreerdp/codec/CMakeLists.txt b/libfreerdp/codec/CMakeLists.txt index ad0180e25..a22433dc2 100644 --- a/libfreerdp/codec/CMakeLists.txt +++ b/libfreerdp/codec/CMakeLists.txt @@ -52,7 +52,8 @@ set(${MODULE_PREFIX}_SRCS mppc.c zgfx.c clear.c - jpeg.c) + jpeg.c + h264.c) set(${MODULE_PREFIX}_SSE2_SRCS rfx_sse2.c @@ -82,8 +83,13 @@ if(WITH_NEON) endif() if(WITH_JPEG) - include_directories(${JPEG_INCLUDE_DIR}) - set(FREERDP_JPEG_LIBS ${JPEG_LIBRARIES}) + include_directories(${JPEG_INCLUDE_DIR}) + set(FREERDP_JPEG_LIBS ${JPEG_LIBRARIES}) +endif() + +if(WITH_OPENH264) + include_directories(${OPENH264_INCLUDE_DIR}) + set(FREERDP_OPENH264_LIBS ${OPENH264_LIBRARIES}) endif() add_complex_library(MODULE ${MODULE_NAME} TYPE "OBJECT" @@ -94,7 +100,8 @@ add_complex_library(MODULE ${MODULE_NAME} TYPE "OBJECT" set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${FREERDP_VERSION} SOVERSION ${FREERDP_API_VERSION} PREFIX "lib") set(${MODULE_PREFIX}_LIBS - ${FREERDP_JPEG_LIBS}) + ${FREERDP_JPEG_LIBS} + ${FREERDP_OPENH264_LIBS}) set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS MONOLITHIC ${MONOLITHIC_BUILD} INTERNAL diff --git a/libfreerdp/codec/h264.c b/libfreerdp/codec/h264.c new file mode 100644 index 000000000..5f8475f32 --- /dev/null +++ b/libfreerdp/codec/h264.c @@ -0,0 +1,281 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * H.264 Bitmap Compression + * + * Copyright 2014 Mike McDonald + * + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include + +#include +#include + +#ifdef WITH_OPENH264 + +#define USE_DUMP_IMAGE 0 +#define USE_GRAY_SCALE 0 + +static UINT32 YUV_to_RGB(BYTE Y, BYTE U, BYTE V) +{ + BYTE R, G, B; + +#if USE_GRAY_SCALE + /* + * Displays the Y plane as a gray-scale image. + */ + R = Y; + G = Y; + B = Y; +#else + /* + * Documented colorspace conversion from YUV to RGB. + * See http://msdn.microsoft.com/en-us/library/ms893078.aspx + */ + +#define clip(x) ((x) & 0xFF) + + int C, D, E; + + C = Y - 16; + D = U - 128; + E = V - 128; + + R = clip(( 298 * C + 409 * E + 128) >> 8); + G = clip(( 298 * C - 100 * D - 208 * E + 128) >> 8); + B = clip(( 298 * C + 516 * D + 128) >> 8); +#endif + + return RGB32(R, G, B); +} + +#if USE_DUMP_IMAGE +static void h264_dump_i420_image(BYTE* imageData, int imageWidth, int imageHeight, int* imageStride) +{ + static int frame_num; + + FILE* fp; + char buffer[64]; + BYTE* yp; + int x, y; + + sprintf(buffer, "/tmp/h264_frame_%d.ppm", frame_num++); + fp = fopen(buffer, "wb"); + fwrite("P5\n", 1, 3, fp); + sprintf(buffer, "%d %d\n", imageWidth, imageHeight); + fwrite(buffer, 1, strlen(buffer), fp); + fwrite("255\n", 1, 4, fp); + + yp = imageData; + for (y = 0; y < imageHeight; y++) + { + fwrite(yp, 1, imageWidth, fp); + yp += imageStride[0]; + } + + fclose(fp); +} +#endif + +int h264_decompress(H264_CONTEXT* h264, BYTE* pSrcData, UINT32 SrcSize, + BYTE** ppDstData, DWORD DstFormat, int nDstStep, int nXDst, int nYDst, int nWidth, int nHeight) +{ + DECODING_STATE state; + SBufferInfo sBufferInfo; + SSysMEMBuffer* pSystemBuffer; + UINT32 UncompressedSize; + BYTE* pDstData; + BYTE* pYUVData[3]; + BYTE* pY; + BYTE* pU; + BYTE* pV; + int Y, U, V; + int i, j; + + if (!h264 || !h264->pDecoder) + return -1; + + printf("h264_decompress: pSrcData=%p, SrcSize=%u, pDstData=%p, DstFormat=%lx, nDstStep=%d, nXDst=%d, nYDst=%d, nWidth=%d, nHeight=%d)\n", + pSrcData, SrcSize, *ppDstData, DstFormat, nDstStep, nXDst, nYDst, nWidth, nHeight); + + /* Allocate a destination buffer (if needed). */ + + UncompressedSize = nWidth * nHeight * 4; + + if (UncompressedSize == 0) + return -1; + + pDstData = *ppDstData; + + if (!pDstData) + { + pDstData = (BYTE*) malloc(UncompressedSize); + + if (!pDstData) + return -1; + + *ppDstData = pDstData; + } + + /* + * Decompress the image. The RDP host only seems to send I420 format. + */ + + pYUVData[0] = NULL; + pYUVData[1] = NULL; + pYUVData[2] = NULL; + + ZeroMemory(&sBufferInfo, sizeof(sBufferInfo)); + + state = (*h264->pDecoder)->DecodeFrame2( + h264->pDecoder, + pSrcData, + SrcSize, + pYUVData, + &sBufferInfo); + + pSystemBuffer = &sBufferInfo.UsrData.sSystemBuffer; + + printf("h264_decompress: state=%u, pYUVData=[%p,%p,%p], bufferStatus=%d, width=%d, height=%d, format=%d, stride=[%d,%d]\n", + state, pYUVData[0], pYUVData[1], pYUVData[2], sBufferInfo.iBufferStatus, + pSystemBuffer->iWidth, pSystemBuffer->iHeight, pSystemBuffer->iFormat, + pSystemBuffer->iStride[0], pSystemBuffer->iStride[1]); + + if (state != 0) + return -1; + + if (!pYUVData[0] || !pYUVData[1] || !pYUVData[2]) + return -1; + + if (sBufferInfo.iBufferStatus != 1) + return -1; + + if (pSystemBuffer->iFormat != videoFormatI420) + return -1; + + /* Convert I420 (same as IYUV) to XRGB. */ + +#if USE_DUMP_IMAGE + h264_dump_i420_image(pY, pSystemBuffer->iWidth, pSystemBuffer->iHeight, pSystemBuffer->iStride); +#endif + + pY = pYUVData[0]; + pU = pYUVData[1]; + pV = pYUVData[2]; + + for (j = 0; j < nHeight; j++) + { + BYTE *pXRGB = pDstData + ((nYDst + j) * nDstStep) + (nXDst * 4); + int y = nYDst + j; + + for (i = 0; i < nWidth; i++) + { + int x = nXDst + i; + + Y = pY[(y * pSystemBuffer->iStride[0]) + x]; + U = pU[(y/2) * pSystemBuffer->iStride[1] + (x/2)]; + V = pV[(y/2) * pSystemBuffer->iStride[1] + (x/2)]; + + *(UINT32*)pXRGB = YUV_to_RGB(Y, U, V); + + pXRGB += 4; + } + } + + return 1; +} + +int h264_compress(H264_CONTEXT* h264, BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstData, UINT32* pDstSize) +{ + return 1; +} + +void h264_context_reset(H264_CONTEXT* h264) +{ +} + +H264_CONTEXT* h264_context_new(BOOL Compressor) +{ + static EVideoFormatType videoFormat = videoFormatI420; + + H264_CONTEXT* h264; + SDecodingParam sDecParam; + long status; + + h264 = (H264_CONTEXT*) calloc(1, sizeof(H264_CONTEXT)); + + if (h264) + { + h264->Compressor = Compressor; + + WelsCreateDecoder(&h264->pDecoder); + + if (!h264->pDecoder) + { + printf("Failed to create OpenH264 decoder\n"); + goto EXCEPTION; + } + + ZeroMemory(&sDecParam, sizeof(sDecParam)); + sDecParam.iOutputColorFormat = videoFormatARGB; + status = (*h264->pDecoder)->Initialize(h264->pDecoder, &sDecParam); + if (status != 0) + { + printf("Failed to initialize OpenH264 decoder (status=%ld)\n", status); + goto EXCEPTION; + } + + status = (*h264->pDecoder)->SetOption(h264->pDecoder, DECODER_OPTION_DATAFORMAT, &videoFormat); + if (status != 0) + { + printf("Failed to set data format option on OpenH264 decoder (status=%ld)\n", status); + } + + h264_context_reset(h264); + } + + return h264; + +EXCEPTION: + if (h264->pDecoder) + { + WelsDestroyDecoder(h264->pDecoder); + } + + free(h264); + + return NULL; +} + +void h264_context_free(H264_CONTEXT* h264) +{ + if (h264) + { + if (h264->pDecoder) + { + (*h264->pDecoder)->Uninitialize(h264->pDecoder); + WelsDestroyDecoder(h264->pDecoder); + } + + free(h264); + } +} + +#endif