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")
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")
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];
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;
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,
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;
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;
}
#include <freerdp/codec/clear.h>
#include <freerdp/codec/color.h>
#include <freerdp/codec/bitmap.h>
+#include <freerdp/codec/h264.h>
#include <freerdp/codec/region.h>
struct xf_WorkArea
RFX_CONTEXT* rfx;
NSC_CONTEXT* nsc;
CLEAR_CONTEXT* clear;
+ H264_CONTEXT* h264;
void* xv_context;
void* clipboard_context;
--- /dev/null
+# - 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)
+
--- /dev/null
+/**
+ * FreeRDP: A Remote Desktop Protocol Implementation
+ * H.264 Bitmap Compression
+ *
+ * Copyright 2014 Mike McDonald <Mike.McDonald@software.dell.com>
+ *
+ * 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 <freerdp/api.h>
+#include <freerdp/types.h>
+
+#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 */
+
mppc.c
zgfx.c
clear.c
- jpeg.c)
+ jpeg.c
+ h264.c)
set(${MODULE_PREFIX}_SSE2_SRCS
rfx_sse2.c
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"
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
--- /dev/null
+/**
+ * FreeRDP: A Remote Desktop Protocol Implementation
+ * H.264 Bitmap Compression
+ *
+ * Copyright 2014 Mike McDonald <Mike.McDonald@software.dell.com>
+ *
+ * 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 <winpr/crt.h>
+#include <winpr/print.h>
+#include <winpr/bitstream.h>
+
+#include <freerdp/codec/color.h>
+#include <freerdp/codec/h264.h>
+
+#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