Initial implementation of H.264 decoder for MS-RDPEGFX
authorMike McDonald <Mike.McDonald@software.dell.com>
Wed, 2 Jul 2014 03:28:09 +0000 (23:28 -0400)
committerMike McDonald <Mike.McDonald@software.dell.com>
Wed, 2 Jul 2014 03:28:09 +0000 (23:28 -0400)
CMakeLists.txt
channels/rdpgfx/client/rdpgfx_main.c
client/X11/xf_gfx.c
client/X11/xfreerdp.h
cmake/FindOpenH264.cmake [new file with mode: 0644]
include/freerdp/codec/h264.h [new file with mode: 0644]
libfreerdp/codec/CMakeLists.txt
libfreerdp/codec/h264.c [new file with mode: 0644]

index 07653d6..20bda93 100755 (executable)
@@ -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")
index 032b51b..575235c 100644 (file)
@@ -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];
index 01ec060..c04b131 100644 (file)
@@ -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;
        }
 
index a1e6ebf..16d7952 100644 (file)
@@ -34,6 +34,7 @@ typedef struct xf_context xfContext;
 #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
@@ -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 (file)
index 0000000..2e06e34
--- /dev/null
@@ -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 (file)
index 0000000..f7f6a13
--- /dev/null
@@ -0,0 +1,60 @@
+/**
+ * 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 */
+
index ad0180e..a22433d 100644 (file)
@@ -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 (file)
index 0000000..5f8475f
--- /dev/null
@@ -0,0 +1,281 @@
+/**
+ * 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