commit
eb5e303328
@ -217,10 +217,6 @@ if(CMAKE_COMPILER_IS_GNUCC)
|
||||
if(CMAKE_BUILD_TYPE STREQUAL "Release")
|
||||
set(CMAKE_C_FLAGS_RELEASE "-DNDEBUG")
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "-DNDEBUG")
|
||||
if(NOT OPENBSD)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O2")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2")
|
||||
endif()
|
||||
|
||||
CHECK_C_COMPILER_FLAG (-Wno-builtin-macro-redefined Wno-builtin-macro-redefined)
|
||||
if(Wno-builtin-macro-redefined)
|
||||
|
@ -38,10 +38,11 @@
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
static UINT rdpgfx_read_h264_metablock(RDPGFX_PLUGIN* gfx, wStream* s, RDPGFX_H264_METABLOCK* meta)
|
||||
static UINT rdpgfx_read_h264_metablock(RDPGFX_PLUGIN* gfx, wStream* s,
|
||||
RDPGFX_H264_METABLOCK* meta)
|
||||
{
|
||||
UINT32 index;
|
||||
RDPGFX_RECT16* regionRect;
|
||||
RECTANGLE_16* regionRect;
|
||||
RDPGFX_H264_QUANT_QUALITY* quantQualityVal;
|
||||
UINT error = ERROR_INVALID_DATA;
|
||||
|
||||
@ -56,13 +57,13 @@ static UINT rdpgfx_read_h264_metablock(RDPGFX_PLUGIN* gfx, wStream* s, RDPGFX_H2
|
||||
|
||||
Stream_Read_UINT32(s, meta->numRegionRects); /* numRegionRects (4 bytes) */
|
||||
|
||||
if (Stream_GetRemainingLength(s) < (meta->numRegionRects * 8))
|
||||
if (Stream_GetRemainingLength(s) < (meta->numRegionRects * sizeof(RECTANGLE_16)))
|
||||
{
|
||||
WLog_ERR(TAG, "not enough data!");
|
||||
goto error_out;
|
||||
}
|
||||
|
||||
meta->regionRects = (RDPGFX_RECT16*) malloc(meta->numRegionRects * sizeof(RDPGFX_RECT16));
|
||||
meta->regionRects = (RECTANGLE_16*) malloc(meta->numRegionRects * sizeof(RECTANGLE_16));
|
||||
|
||||
if (!meta->regionRects)
|
||||
{
|
||||
@ -128,11 +129,11 @@ error_out:
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
static UINT rdpgfx_decode_h264(RDPGFX_PLUGIN* gfx, RDPGFX_SURFACE_COMMAND* cmd)
|
||||
static UINT rdpgfx_decode_AVC420(RDPGFX_PLUGIN* gfx, RDPGFX_SURFACE_COMMAND* cmd)
|
||||
{
|
||||
UINT error;
|
||||
wStream* s;
|
||||
RDPGFX_H264_BITMAP_STREAM h264;
|
||||
RDPGFX_AVC420_BITMAP_STREAM h264;
|
||||
RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface;
|
||||
|
||||
s = Stream_New(cmd->data, cmd->length);
|
||||
@ -169,6 +170,91 @@ static UINT rdpgfx_decode_h264(RDPGFX_PLUGIN* gfx, RDPGFX_SURFACE_COMMAND* cmd)
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function description
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
static UINT rdpgfx_decode_AVC444(RDPGFX_PLUGIN* gfx, RDPGFX_SURFACE_COMMAND* cmd)
|
||||
{
|
||||
UINT error;
|
||||
UINT32 tmp;
|
||||
size_t pos1, pos2;
|
||||
wStream* s;
|
||||
RDPGFX_AVC444_BITMAP_STREAM h264;
|
||||
RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface;
|
||||
|
||||
s = Stream_New(cmd->data, cmd->length);
|
||||
|
||||
if (!s)
|
||||
{
|
||||
WLog_ERR(TAG, "Stream_New failed!");
|
||||
return CHANNEL_RC_NO_MEMORY;
|
||||
}
|
||||
|
||||
if (Stream_GetRemainingLength(s) < 4)
|
||||
return ERROR_INVALID_DATA;
|
||||
|
||||
Stream_Read_UINT32(s, tmp);
|
||||
h264.cbAvc420EncodedBitstream1 = tmp & 0x3FFFFFFFUL;
|
||||
h264.LC = (tmp >> 30UL) & 0x03UL;
|
||||
|
||||
if (h264.LC == 0x03)
|
||||
return ERROR_INVALID_DATA;
|
||||
|
||||
pos1 = Stream_GetPosition(s);
|
||||
if ((error = rdpgfx_read_h264_metablock(gfx, s, &(h264.bitstream[0].meta))))
|
||||
{
|
||||
WLog_ERR(TAG, "rdpgfx_read_h264_metablock failed with error %lu!", error);
|
||||
return error;
|
||||
}
|
||||
pos2 = Stream_GetPosition(s);
|
||||
|
||||
h264.bitstream[0].data = Stream_Pointer(s);
|
||||
|
||||
if (h264.LC == 0)
|
||||
{
|
||||
tmp = h264.cbAvc420EncodedBitstream1 - pos2 + pos1;
|
||||
if (Stream_GetRemainingLength(s) < tmp)
|
||||
return ERROR_INVALID_DATA;
|
||||
|
||||
h264.bitstream[0].length = tmp;
|
||||
Stream_Seek(s, tmp);
|
||||
|
||||
if ((error = rdpgfx_read_h264_metablock(gfx, s, &(h264.bitstream[1].meta))))
|
||||
{
|
||||
WLog_ERR(TAG, "rdpgfx_read_h264_metablock failed with error %lu!", error);
|
||||
return error;
|
||||
}
|
||||
|
||||
h264.bitstream[1].data = Stream_Pointer(s);
|
||||
h264.bitstream[1].length = Stream_GetRemainingLength(s);
|
||||
}
|
||||
else
|
||||
{
|
||||
h264.bitstream[0].length = Stream_GetRemainingLength(s);
|
||||
memset(&h264.bitstream[1], 0, sizeof(h264.bitstream[1]));
|
||||
}
|
||||
|
||||
Stream_Free(s, FALSE);
|
||||
|
||||
cmd->extra = (void*) &h264;
|
||||
|
||||
if (context)
|
||||
{
|
||||
IFCALLRET(context->SurfaceCommand, error, context, cmd);
|
||||
if (error)
|
||||
WLog_ERR(TAG, "context->SurfaceCommand failed with error %lu", error);
|
||||
}
|
||||
|
||||
free(h264.bitstream[0].meta.regionRects);
|
||||
free(h264.bitstream[0].meta.quantQualityVals);
|
||||
free(h264.bitstream[1].meta.regionRects);
|
||||
free(h264.bitstream[1].meta.quantQualityVals);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function description
|
||||
*
|
||||
@ -181,10 +267,18 @@ UINT rdpgfx_decode(RDPGFX_PLUGIN* gfx, RDPGFX_SURFACE_COMMAND* cmd)
|
||||
|
||||
switch (cmd->codecId)
|
||||
{
|
||||
case RDPGFX_CODECID_H264:
|
||||
if ((error = rdpgfx_decode_h264(gfx, cmd)))
|
||||
case RDPGFX_CODECID_AVC420:
|
||||
if ((error = rdpgfx_decode_AVC420(gfx, cmd)))
|
||||
{
|
||||
WLog_ERR(TAG, "rdpgfx_decode_h264 failed with error %lu", error);
|
||||
WLog_ERR(TAG, "rdpgfx_decode_AVC420 failed with error %lu", error);
|
||||
return error;
|
||||
}
|
||||
break;
|
||||
|
||||
case RDPGFX_CODECID_AVC444:
|
||||
if ((error = rdpgfx_decode_AVC444(gfx, cmd)))
|
||||
{
|
||||
WLog_ERR(TAG, "rdpgfx_decode_AVC444 failed with error %lu", error);
|
||||
return error;
|
||||
}
|
||||
break;
|
||||
|
@ -77,8 +77,10 @@ const char* rdpgfx_get_codec_id_string(UINT16 codecId)
|
||||
return "RDPGFX_CODECID_CLEARCODEC";
|
||||
case RDPGFX_CODECID_PLANAR:
|
||||
return "RDPGFX_CODECID_PLANAR";
|
||||
case RDPGFX_CODECID_H264:
|
||||
return "RDPGFX_CODECID_H264";
|
||||
case RDPGFX_CODECID_AVC420:
|
||||
return "RDPGFX_CODECID_AVC420";
|
||||
case RDPGFX_CODECID_AVC444:
|
||||
return "RDPGFX_CODECID_AVC444";
|
||||
case RDPGFX_CODECID_ALPHA:
|
||||
return "RDPGFX_CODECID_ALPHA";
|
||||
case RDPGFX_CODECID_CAPROGRESSIVE:
|
||||
@ -161,7 +163,7 @@ UINT rdpgfx_write_point16(wStream* s, RDPGFX_POINT16* point16)
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
UINT rdpgfx_read_rect16(wStream* s, RDPGFX_RECT16* rect16)
|
||||
UINT rdpgfx_read_rect16(wStream* s, RECTANGLE_16* rect16)
|
||||
{
|
||||
if (Stream_GetRemainingLength(s) < 8)
|
||||
{
|
||||
@ -182,7 +184,7 @@ UINT rdpgfx_read_rect16(wStream* s, RDPGFX_RECT16* rect16)
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
UINT rdpgfx_write_rect16(wStream* s, RDPGFX_RECT16* rect16)
|
||||
UINT rdpgfx_write_rect16(wStream* s, RECTANGLE_16* rect16)
|
||||
{
|
||||
Stream_Write_UINT16(s, rect16->left); /* left (2 bytes) */
|
||||
Stream_Write_UINT16(s, rect16->top); /* top (2 bytes) */
|
||||
|
@ -36,8 +36,8 @@ UINT rdpgfx_write_header(wStream* s, RDPGFX_HEADER* header);
|
||||
UINT rdpgfx_read_point16(wStream* s, RDPGFX_POINT16* pt16);
|
||||
UINT rdpgfx_write_point16(wStream* s, RDPGFX_POINT16* point16);
|
||||
|
||||
UINT rdpgfx_read_rect16(wStream* s, RDPGFX_RECT16* rect16);
|
||||
UINT rdpgfx_write_rect16(wStream* s, RDPGFX_RECT16* rect16);
|
||||
UINT rdpgfx_read_rect16(wStream* s, RECTANGLE_16* rect16);
|
||||
UINT rdpgfx_write_rect16(wStream* s, RECTANGLE_16* rect16);
|
||||
|
||||
UINT rdpgfx_read_color32(wStream* s, RDPGFX_COLOR32* color32);
|
||||
UINT rdpgfx_write_color32(wStream* s, RDPGFX_COLOR32* color32);
|
||||
|
@ -58,7 +58,7 @@ static UINT rdpgfx_send_caps_advertise_pdu(RDPGFX_CHANNEL_CALLBACK* callback)
|
||||
RDPGFX_PLUGIN* gfx;
|
||||
RDPGFX_HEADER header;
|
||||
RDPGFX_CAPSET* capsSet;
|
||||
RDPGFX_CAPSET capsSets[2];
|
||||
RDPGFX_CAPSET capsSets[3];
|
||||
RDPGFX_CAPS_ADVERTISE_PDU pdu;
|
||||
|
||||
gfx = (RDPGFX_PLUGIN*) callback->plugin;
|
||||
@ -90,7 +90,17 @@ static UINT rdpgfx_send_caps_advertise_pdu(RDPGFX_CHANNEL_CALLBACK* callback)
|
||||
capsSet->flags |= RDPGFX_CAPS_FLAG_SMALL_CACHE;
|
||||
|
||||
if (gfx->H264)
|
||||
capsSet->flags |= RDPGFX_CAPS_FLAG_H264ENABLED;
|
||||
capsSet->flags |= RDPGFX_CAPS_FLAG_AVC420_ENABLED;
|
||||
|
||||
capsSet = &capsSets[pdu.capsSetCount++];
|
||||
capsSet->version = RDPGFX_CAPVERSION_10;
|
||||
capsSet->flags = 0;
|
||||
|
||||
if (gfx->SmallCache)
|
||||
capsSet->flags |= RDPGFX_CAPS_FLAG_SMALL_CACHE;
|
||||
|
||||
if (!gfx->H264)
|
||||
capsSet->flags |= RDPGFX_CAPS_FLAG_AVC_DISABLED;
|
||||
|
||||
header.pduLength = RDPGFX_HEADER_SIZE + 2 + (pdu.capsSetCount * RDPGFX_CAPSET_SIZE);
|
||||
|
||||
@ -688,7 +698,7 @@ static UINT rdpgfx_recv_delete_encoding_context_pdu(RDPGFX_CHANNEL_CALLBACK* cal
|
||||
UINT rdpgfx_recv_solid_fill_pdu(RDPGFX_CHANNEL_CALLBACK* callback, wStream* s)
|
||||
{
|
||||
UINT16 index;
|
||||
RDPGFX_RECT16* fillRect;
|
||||
RECTANGLE_16* fillRect;
|
||||
RDPGFX_SOLID_FILL_PDU pdu;
|
||||
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin;
|
||||
RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface;
|
||||
@ -714,7 +724,7 @@ UINT rdpgfx_recv_solid_fill_pdu(RDPGFX_CHANNEL_CALLBACK* callback, wStream* s)
|
||||
return ERROR_INVALID_DATA;
|
||||
}
|
||||
|
||||
pdu.fillRects = (RDPGFX_RECT16*) calloc(pdu.fillRectCount, sizeof(RDPGFX_RECT16));
|
||||
pdu.fillRects = (RECTANGLE_16*) calloc(pdu.fillRectCount, sizeof(RECTANGLE_16));
|
||||
|
||||
if (!pdu.fillRects)
|
||||
{
|
||||
@ -742,7 +752,7 @@ UINT rdpgfx_recv_solid_fill_pdu(RDPGFX_CHANNEL_CALLBACK* callback, wStream* s)
|
||||
if (error)
|
||||
WLog_ERR(TAG, "context->SolidFill failed with error %lu", error);
|
||||
}
|
||||
|
||||
|
||||
free(pdu.fillRects);
|
||||
|
||||
return error;
|
||||
|
@ -31,7 +31,7 @@
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
UINT xf_ResetGraphics(RdpgfxClientContext* context, RDPGFX_RESET_GRAPHICS_PDU* resetGraphics)
|
||||
static UINT xf_ResetGraphics(RdpgfxClientContext* context, RDPGFX_RESET_GRAPHICS_PDU* resetGraphics)
|
||||
{
|
||||
int index;
|
||||
UINT16 count;
|
||||
@ -70,7 +70,7 @@ UINT xf_ResetGraphics(RdpgfxClientContext* context, RDPGFX_RESET_GRAPHICS_PDU* r
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
int xf_OutputUpdate(xfContext* xfc, xfGfxSurface* surface)
|
||||
static int xf_OutputUpdate(xfContext* xfc, xfGfxSurface* surface)
|
||||
{
|
||||
UINT16 width, height;
|
||||
UINT32 surfaceX, surfaceY;
|
||||
@ -132,7 +132,7 @@ int xf_OutputUpdate(xfContext* xfc, xfGfxSurface* surface)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int xf_UpdateSurfaces(xfContext* xfc)
|
||||
static int xf_UpdateSurfaces(xfContext* xfc)
|
||||
{
|
||||
UINT16 count;
|
||||
int index;
|
||||
@ -220,7 +220,7 @@ int xf_OutputExpose(xfContext* xfc, int x, int y, int width, int height)
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
UINT xf_StartFrame(RdpgfxClientContext* context, RDPGFX_START_FRAME_PDU* startFrame)
|
||||
static UINT xf_StartFrame(RdpgfxClientContext* context, RDPGFX_START_FRAME_PDU* startFrame)
|
||||
{
|
||||
xfContext* xfc = (xfContext*) context->custom;
|
||||
|
||||
@ -234,7 +234,7 @@ UINT xf_StartFrame(RdpgfxClientContext* context, RDPGFX_START_FRAME_PDU* startFr
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
UINT xf_EndFrame(RdpgfxClientContext* context, RDPGFX_END_FRAME_PDU* endFrame)
|
||||
static UINT xf_EndFrame(RdpgfxClientContext* context, RDPGFX_END_FRAME_PDU* endFrame)
|
||||
{
|
||||
xfContext* xfc = (xfContext*) context->custom;
|
||||
|
||||
@ -250,7 +250,7 @@ UINT xf_EndFrame(RdpgfxClientContext* context, RDPGFX_END_FRAME_PDU* endFrame)
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
UINT xf_SurfaceCommand_Uncompressed(xfContext* xfc, RdpgfxClientContext* context, RDPGFX_SURFACE_COMMAND* cmd)
|
||||
static UINT xf_SurfaceCommand_Uncompressed(xfContext* xfc, RdpgfxClientContext* context, RDPGFX_SURFACE_COMMAND* cmd)
|
||||
{
|
||||
xfGfxSurface* surface;
|
||||
RECTANGLE_16 invalidRect;
|
||||
@ -281,7 +281,7 @@ UINT xf_SurfaceCommand_Uncompressed(xfContext* xfc, RdpgfxClientContext* context
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
UINT xf_SurfaceCommand_RemoteFX(xfContext* xfc, RdpgfxClientContext* context, RDPGFX_SURFACE_COMMAND* cmd)
|
||||
static UINT xf_SurfaceCommand_RemoteFX(xfContext* xfc, RdpgfxClientContext* context, RDPGFX_SURFACE_COMMAND* cmd)
|
||||
{
|
||||
int j;
|
||||
UINT16 i;
|
||||
@ -371,7 +371,7 @@ UINT xf_SurfaceCommand_RemoteFX(xfContext* xfc, RdpgfxClientContext* context, RD
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
UINT xf_SurfaceCommand_ClearCodec(xfContext* xfc, RdpgfxClientContext* context, RDPGFX_SURFACE_COMMAND* cmd)
|
||||
static UINT xf_SurfaceCommand_ClearCodec(xfContext* xfc, RdpgfxClientContext* context, RDPGFX_SURFACE_COMMAND* cmd)
|
||||
{
|
||||
int status;
|
||||
BYTE* DstData = NULL;
|
||||
@ -415,7 +415,7 @@ UINT xf_SurfaceCommand_ClearCodec(xfContext* xfc, RdpgfxClientContext* context,
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
UINT xf_SurfaceCommand_Planar(xfContext* xfc, RdpgfxClientContext* context, RDPGFX_SURFACE_COMMAND* cmd)
|
||||
static UINT xf_SurfaceCommand_Planar(xfContext* xfc, RdpgfxClientContext* context, RDPGFX_SURFACE_COMMAND* cmd)
|
||||
{
|
||||
int status;
|
||||
BYTE* DstData = NULL;
|
||||
@ -453,45 +453,46 @@ UINT xf_SurfaceCommand_Planar(xfContext* xfc, RdpgfxClientContext* context, RDPG
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
UINT xf_SurfaceCommand_H264(xfContext* xfc, RdpgfxClientContext* context, RDPGFX_SURFACE_COMMAND* cmd)
|
||||
static UINT xf_SurfaceCommand_AVC420(xfContext* xfc, RdpgfxClientContext* context, RDPGFX_SURFACE_COMMAND* cmd)
|
||||
{
|
||||
int status;
|
||||
UINT32 i;
|
||||
BYTE* DstData = NULL;
|
||||
xfGfxSurface* surface;
|
||||
RDPGFX_H264_METABLOCK* meta;
|
||||
RDPGFX_H264_BITMAP_STREAM* bs;
|
||||
RDPGFX_AVC420_BITMAP_STREAM* bs;
|
||||
|
||||
surface = (xfGfxSurface*) context->GetSurfaceData(context, cmd->surfaceId);
|
||||
|
||||
if (!surface)
|
||||
return ERROR_INTERNAL_ERROR;
|
||||
|
||||
if (!freerdp_client_codecs_prepare(surface->codecs, FREERDP_CODEC_H264))
|
||||
if (!freerdp_client_codecs_prepare(surface->codecs, FREERDP_CODEC_AVC420))
|
||||
return ERROR_INTERNAL_ERROR;
|
||||
|
||||
bs = (RDPGFX_H264_BITMAP_STREAM*) cmd->extra;
|
||||
bs = (RDPGFX_AVC420_BITMAP_STREAM*) cmd->extra;
|
||||
|
||||
if (!bs)
|
||||
return ERROR_INTERNAL_ERROR;
|
||||
|
||||
meta = &(bs->meta);
|
||||
|
||||
DstData = surface->data;
|
||||
|
||||
status = h264_decompress(surface->codecs->h264, bs->data, bs->length, &DstData,
|
||||
surface->format, surface->scanline , surface->width,
|
||||
surface->height, meta->regionRects, meta->numRegionRects);
|
||||
status = avc420_decompress(surface->codecs->h264, bs->data, bs->length,
|
||||
surface->data, surface->format,
|
||||
surface->scanline , surface->width,
|
||||
surface->height, meta->regionRects,
|
||||
meta->numRegionRects);
|
||||
|
||||
if (status < 0)
|
||||
{
|
||||
WLog_WARN(TAG, "h264_decompress failure: %d, ignoring update.", status);
|
||||
WLog_WARN(TAG, "avc420_decompress failure: %d, ignoring update.", status);
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
for (i = 0; i < meta->numRegionRects; i++)
|
||||
{
|
||||
region16_union_rect(&surface->invalidRegion, &surface->invalidRegion, (RECTANGLE_16*) &(meta->regionRects[i]));
|
||||
region16_union_rect(&surface->invalidRegion,
|
||||
&surface->invalidRegion,
|
||||
&(meta->regionRects[i]));
|
||||
}
|
||||
|
||||
if (!xfc->inGfxFrame)
|
||||
@ -505,7 +506,77 @@ UINT xf_SurfaceCommand_H264(xfContext* xfc, RdpgfxClientContext* context, RDPGFX
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
UINT xf_SurfaceCommand_Alpha(xfContext* xfc, RdpgfxClientContext* context, RDPGFX_SURFACE_COMMAND* cmd)
|
||||
static UINT xf_SurfaceCommand_AVC444(xfContext* xfc, RdpgfxClientContext* context, RDPGFX_SURFACE_COMMAND* cmd)
|
||||
{
|
||||
int status;
|
||||
UINT32 i;
|
||||
xfGfxSurface* surface;
|
||||
RDPGFX_AVC444_BITMAP_STREAM* bs;
|
||||
RDPGFX_AVC420_BITMAP_STREAM* avc1;
|
||||
RDPGFX_AVC420_BITMAP_STREAM* avc2;
|
||||
RDPGFX_H264_METABLOCK* meta1;
|
||||
RDPGFX_H264_METABLOCK* meta2;
|
||||
RECTANGLE_16* regionRects = NULL;
|
||||
|
||||
surface = (xfGfxSurface*) context->GetSurfaceData(context, cmd->surfaceId);
|
||||
|
||||
if (!surface)
|
||||
return ERROR_INTERNAL_ERROR;
|
||||
|
||||
if (!freerdp_client_codecs_prepare(surface->codecs, FREERDP_CODEC_AVC444))
|
||||
return ERROR_INTERNAL_ERROR;
|
||||
|
||||
bs = (RDPGFX_AVC444_BITMAP_STREAM*) cmd->extra;
|
||||
|
||||
if (!bs)
|
||||
return ERROR_INTERNAL_ERROR;
|
||||
|
||||
avc1 = &bs->bitstream[0];
|
||||
avc2 = &bs->bitstream[1];
|
||||
meta1 = &avc1->meta;
|
||||
meta2 = &avc2->meta;
|
||||
|
||||
status = avc444_decompress(surface->codecs->h264, bs->LC,
|
||||
meta1->regionRects, meta1->numRegionRects,
|
||||
avc1->data, avc1->length,
|
||||
meta2->regionRects, meta2->numRegionRects,
|
||||
avc2->data, avc2->length, surface->data,
|
||||
surface->format, surface->scanline,
|
||||
surface->width, surface->height);
|
||||
|
||||
if (status < 0)
|
||||
{
|
||||
WLog_WARN(TAG, "avc444_decompress failure: %d, ignoring update.", status);
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
for (i = 0; i < meta1->numRegionRects; 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]));
|
||||
}
|
||||
|
||||
if (!xfc->inGfxFrame)
|
||||
xf_UpdateSurfaces(xfc);
|
||||
|
||||
free (regionRects);
|
||||
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function description
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
static UINT xf_SurfaceCommand_Alpha(xfContext* xfc, RdpgfxClientContext* context, RDPGFX_SURFACE_COMMAND* cmd)
|
||||
{
|
||||
int status = 0;
|
||||
xfGfxSurface* surface;
|
||||
@ -543,7 +614,7 @@ UINT xf_SurfaceCommand_Alpha(xfContext* xfc, RdpgfxClientContext* context, RDPGF
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
UINT xf_SurfaceCommand_Progressive(xfContext* xfc, RdpgfxClientContext* context, RDPGFX_SURFACE_COMMAND* cmd)
|
||||
static UINT xf_SurfaceCommand_Progressive(xfContext* xfc, RdpgfxClientContext* context, RDPGFX_SURFACE_COMMAND* cmd)
|
||||
{
|
||||
int i, j;
|
||||
int status;
|
||||
@ -645,7 +716,7 @@ UINT xf_SurfaceCommand_Progressive(xfContext* xfc, RdpgfxClientContext* context,
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
UINT xf_SurfaceCommand(RdpgfxClientContext* context, RDPGFX_SURFACE_COMMAND* cmd)
|
||||
static UINT xf_SurfaceCommand(RdpgfxClientContext* context, RDPGFX_SURFACE_COMMAND* cmd)
|
||||
{
|
||||
UINT status = CHANNEL_RC_OK;
|
||||
xfContext* xfc = (xfContext*) context->custom;
|
||||
@ -668,8 +739,12 @@ UINT xf_SurfaceCommand(RdpgfxClientContext* context, RDPGFX_SURFACE_COMMAND* cmd
|
||||
status = xf_SurfaceCommand_Planar(xfc, context, cmd);
|
||||
break;
|
||||
|
||||
case RDPGFX_CODECID_H264:
|
||||
status = xf_SurfaceCommand_H264(xfc, context, cmd);
|
||||
case RDPGFX_CODECID_AVC420:
|
||||
status = xf_SurfaceCommand_AVC420(xfc, context, cmd);
|
||||
break;
|
||||
|
||||
case RDPGFX_CODECID_AVC444:
|
||||
status = xf_SurfaceCommand_AVC444(xfc, context, cmd);
|
||||
break;
|
||||
|
||||
case RDPGFX_CODECID_ALPHA:
|
||||
@ -697,7 +772,7 @@ UINT xf_SurfaceCommand(RdpgfxClientContext* context, RDPGFX_SURFACE_COMMAND* cmd
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
UINT xf_DeleteEncodingContext(RdpgfxClientContext* context, RDPGFX_DELETE_ENCODING_CONTEXT_PDU* deleteEncodingContext)
|
||||
static UINT xf_DeleteEncodingContext(RdpgfxClientContext* context, RDPGFX_DELETE_ENCODING_CONTEXT_PDU* deleteEncodingContext)
|
||||
{
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
@ -707,7 +782,7 @@ UINT xf_DeleteEncodingContext(RdpgfxClientContext* context, RDPGFX_DELETE_ENCODI
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
UINT xf_CreateSurface(RdpgfxClientContext* context, RDPGFX_CREATE_SURFACE_PDU* createSurface)
|
||||
static UINT xf_CreateSurface(RdpgfxClientContext* context, RDPGFX_CREATE_SURFACE_PDU* createSurface)
|
||||
{
|
||||
size_t size;
|
||||
UINT32 bytesPerPixel;
|
||||
@ -795,7 +870,7 @@ UINT xf_CreateSurface(RdpgfxClientContext* context, RDPGFX_CREATE_SURFACE_PDU* c
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
UINT xf_DeleteSurface(RdpgfxClientContext* context, RDPGFX_DELETE_SURFACE_PDU* deleteSurface)
|
||||
static UINT xf_DeleteSurface(RdpgfxClientContext* context, RDPGFX_DELETE_SURFACE_PDU* deleteSurface)
|
||||
{
|
||||
rdpCodecs* codecs = NULL;
|
||||
xfGfxSurface* surface = NULL;
|
||||
@ -827,13 +902,13 @@ UINT xf_DeleteSurface(RdpgfxClientContext* context, RDPGFX_DELETE_SURFACE_PDU* d
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
UINT xf_SolidFill(RdpgfxClientContext* context, RDPGFX_SOLID_FILL_PDU* solidFill)
|
||||
static UINT xf_SolidFill(RdpgfxClientContext* context, RDPGFX_SOLID_FILL_PDU* solidFill)
|
||||
{
|
||||
UINT16 index;
|
||||
UINT32 color;
|
||||
BYTE a, r, g, b;
|
||||
int nWidth, nHeight;
|
||||
RDPGFX_RECT16* rect;
|
||||
RECTANGLE_16* rect;
|
||||
xfGfxSurface* surface;
|
||||
RECTANGLE_16 invalidRect;
|
||||
xfContext* xfc = (xfContext*) context->custom;
|
||||
@ -879,12 +954,12 @@ UINT xf_SolidFill(RdpgfxClientContext* context, RDPGFX_SOLID_FILL_PDU* solidFill
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
UINT xf_SurfaceToSurface(RdpgfxClientContext* context, RDPGFX_SURFACE_TO_SURFACE_PDU* surfaceToSurface)
|
||||
static UINT xf_SurfaceToSurface(RdpgfxClientContext* context, RDPGFX_SURFACE_TO_SURFACE_PDU* surfaceToSurface)
|
||||
{
|
||||
UINT16 index;
|
||||
BOOL sameSurface;
|
||||
int nWidth, nHeight;
|
||||
RDPGFX_RECT16* rectSrc;
|
||||
RECTANGLE_16* rectSrc;
|
||||
RDPGFX_POINT16* destPt;
|
||||
RECTANGLE_16 invalidRect;
|
||||
xfGfxSurface* surfaceSrc;
|
||||
@ -944,10 +1019,10 @@ UINT xf_SurfaceToSurface(RdpgfxClientContext* context, RDPGFX_SURFACE_TO_SURFACE
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
UINT xf_SurfaceToCache(RdpgfxClientContext* context, RDPGFX_SURFACE_TO_CACHE_PDU* surfaceToCache)
|
||||
static UINT xf_SurfaceToCache(RdpgfxClientContext* context, RDPGFX_SURFACE_TO_CACHE_PDU* surfaceToCache)
|
||||
{
|
||||
size_t size;
|
||||
RDPGFX_RECT16* rect;
|
||||
RECTANGLE_16* rect;
|
||||
xfGfxSurface* surface;
|
||||
xfGfxCacheEntry* cacheEntry;
|
||||
xfContext* xfc = (xfContext*) context->custom;
|
||||
@ -997,7 +1072,7 @@ UINT xf_SurfaceToCache(RdpgfxClientContext* context, RDPGFX_SURFACE_TO_CACHE_PDU
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
UINT xf_CacheToSurface(RdpgfxClientContext* context, RDPGFX_CACHE_TO_SURFACE_PDU* cacheToSurface)
|
||||
static UINT xf_CacheToSurface(RdpgfxClientContext* context, RDPGFX_CACHE_TO_SURFACE_PDU* cacheToSurface)
|
||||
{
|
||||
UINT16 index;
|
||||
RDPGFX_POINT16* destPt;
|
||||
@ -1039,7 +1114,7 @@ UINT xf_CacheToSurface(RdpgfxClientContext* context, RDPGFX_CACHE_TO_SURFACE_PDU
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
UINT xf_CacheImportReply(RdpgfxClientContext* context, RDPGFX_CACHE_IMPORT_REPLY_PDU* cacheImportReply)
|
||||
static UINT xf_CacheImportReply(RdpgfxClientContext* context, RDPGFX_CACHE_IMPORT_REPLY_PDU* cacheImportReply)
|
||||
{
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
@ -1049,7 +1124,7 @@ UINT xf_CacheImportReply(RdpgfxClientContext* context, RDPGFX_CACHE_IMPORT_REPLY
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
UINT xf_EvictCacheEntry(RdpgfxClientContext* context, RDPGFX_EVICT_CACHE_ENTRY_PDU* evictCacheEntry)
|
||||
static UINT xf_EvictCacheEntry(RdpgfxClientContext* context, RDPGFX_EVICT_CACHE_ENTRY_PDU* evictCacheEntry)
|
||||
{
|
||||
xfGfxCacheEntry* cacheEntry;
|
||||
|
||||
@ -1071,7 +1146,7 @@ UINT xf_EvictCacheEntry(RdpgfxClientContext* context, RDPGFX_EVICT_CACHE_ENTRY_P
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
UINT xf_MapSurfaceToOutput(RdpgfxClientContext* context, RDPGFX_MAP_SURFACE_TO_OUTPUT_PDU* surfaceToOutput)
|
||||
static UINT xf_MapSurfaceToOutput(RdpgfxClientContext* context, RDPGFX_MAP_SURFACE_TO_OUTPUT_PDU* surfaceToOutput)
|
||||
{
|
||||
xfGfxSurface* surface;
|
||||
|
||||
@ -1094,7 +1169,7 @@ UINT xf_MapSurfaceToOutput(RdpgfxClientContext* context, RDPGFX_MAP_SURFACE_TO_O
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
UINT xf_MapSurfaceToWindow(RdpgfxClientContext* context, RDPGFX_MAP_SURFACE_TO_WINDOW_PDU* surfaceToWindow)
|
||||
static UINT xf_MapSurfaceToWindow(RdpgfxClientContext* context, RDPGFX_MAP_SURFACE_TO_WINDOW_PDU* surfaceToWindow)
|
||||
{
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
@ -37,15 +37,6 @@ struct _RDPGFX_POINT16
|
||||
};
|
||||
typedef struct _RDPGFX_POINT16 RDPGFX_POINT16;
|
||||
|
||||
struct _RDPGFX_RECT16
|
||||
{
|
||||
UINT16 left;
|
||||
UINT16 top;
|
||||
UINT16 right;
|
||||
UINT16 bottom;
|
||||
};
|
||||
typedef struct _RDPGFX_RECT16 RDPGFX_RECT16;
|
||||
|
||||
struct _RDPGFX_COLOR32
|
||||
{
|
||||
BYTE B;
|
||||
@ -99,6 +90,7 @@ typedef struct _RDPGFX_HEADER RDPGFX_HEADER;
|
||||
|
||||
#define RDPGFX_CAPVERSION_8 0x00080004
|
||||
#define RDPGFX_CAPVERSION_81 0x00080105
|
||||
#define RDPGFX_CAPVERSION_10 0x000A0002
|
||||
|
||||
#define RDPGFX_CAPSET_SIZE 12
|
||||
|
||||
@ -111,7 +103,8 @@ typedef struct _RDPGFX_CAPSET RDPGFX_CAPSET;
|
||||
|
||||
#define RDPGFX_CAPS_FLAG_THINCLIENT 0x00000001 /* 8.0+ */
|
||||
#define RDPGFX_CAPS_FLAG_SMALL_CACHE 0x00000002 /* 8.0+ */
|
||||
#define RDPGFX_CAPS_FLAG_H264ENABLED 0x00000010 /* 8.1+ */
|
||||
#define RDPGFX_CAPS_FLAG_AVC420_ENABLED 0x00000010 /* 8.1+ */
|
||||
#define RDPGFX_CAPS_FLAG_AVC_DISABLED 0x00000020 /* 10.0+ */
|
||||
|
||||
struct _RDPGFX_CAPSET_VERSION8
|
||||
{
|
||||
@ -129,6 +122,14 @@ struct _RDPGFX_CAPSET_VERSION81
|
||||
};
|
||||
typedef struct _RDPGFX_CAPSET_VERSION81 RDPGFX_CAPSET_VERSION81;
|
||||
|
||||
struct _RDPGFX_CAPSET_VERSION10
|
||||
{
|
||||
UINT32 version;
|
||||
UINT32 capsDataLength;
|
||||
UINT32 flags;
|
||||
};
|
||||
typedef struct _RDPGFX_CAPSET_VERSION10 RDPGFX_CAPSET_VERSION10;
|
||||
|
||||
/**
|
||||
* Graphics Messages
|
||||
*/
|
||||
@ -137,15 +138,16 @@ typedef struct _RDPGFX_CAPSET_VERSION81 RDPGFX_CAPSET_VERSION81;
|
||||
#define RDPGFX_CODECID_CAVIDEO 0x0003
|
||||
#define RDPGFX_CODECID_CLEARCODEC 0x0008
|
||||
#define RDPGFX_CODECID_PLANAR 0x000A
|
||||
#define RDPGFX_CODECID_H264 0x000B
|
||||
#define RDPGFX_CODECID_AVC420 0x000B
|
||||
#define RDPGFX_CODECID_ALPHA 0x000C
|
||||
#define RDPGFX_CODECID_AVC444 0x000E
|
||||
|
||||
struct _RDPGFX_WIRE_TO_SURFACE_PDU_1
|
||||
{
|
||||
UINT16 surfaceId;
|
||||
UINT16 codecId;
|
||||
RDPGFX_PIXELFORMAT pixelFormat;
|
||||
RDPGFX_RECT16 destRect;
|
||||
RECTANGLE_16 destRect;
|
||||
UINT32 bitmapDataLength;
|
||||
BYTE* bitmapData;
|
||||
};
|
||||
@ -195,7 +197,7 @@ struct _RDPGFX_SOLID_FILL_PDU
|
||||
UINT16 surfaceId;
|
||||
RDPGFX_COLOR32 fillPixel;
|
||||
UINT16 fillRectCount;
|
||||
RDPGFX_RECT16* fillRects;
|
||||
RECTANGLE_16* fillRects;
|
||||
};
|
||||
typedef struct _RDPGFX_SOLID_FILL_PDU RDPGFX_SOLID_FILL_PDU;
|
||||
|
||||
@ -203,7 +205,7 @@ struct _RDPGFX_SURFACE_TO_SURFACE_PDU
|
||||
{
|
||||
UINT16 surfaceIdSrc;
|
||||
UINT16 surfaceIdDest;
|
||||
RDPGFX_RECT16 rectSrc;
|
||||
RECTANGLE_16 rectSrc;
|
||||
UINT16 destPtsCount;
|
||||
RDPGFX_POINT16* destPts;
|
||||
};
|
||||
@ -214,7 +216,7 @@ struct _RDPGFX_SURFACE_TO_CACHE_PDU
|
||||
UINT16 surfaceId;
|
||||
UINT64 cacheKey;
|
||||
UINT16 cacheSlot;
|
||||
RDPGFX_RECT16 rectSrc;
|
||||
RECTANGLE_16 rectSrc;
|
||||
};
|
||||
typedef struct _RDPGFX_SURFACE_TO_CACHE_PDU RDPGFX_SURFACE_TO_CACHE_PDU;
|
||||
|
||||
@ -349,18 +351,27 @@ typedef struct _RDPGFX_H264_QUANT_QUALITY RDPGFX_H264_QUANT_QUALITY;
|
||||
struct _RDPGFX_H264_METABLOCK
|
||||
{
|
||||
UINT32 numRegionRects;
|
||||
RDPGFX_RECT16* regionRects;
|
||||
RECTANGLE_16* regionRects;
|
||||
RDPGFX_H264_QUANT_QUALITY* quantQualityVals;
|
||||
};
|
||||
typedef struct _RDPGFX_H264_METABLOCK RDPGFX_H264_METABLOCK;
|
||||
|
||||
struct _RDPGFX_H264_BITMAP_STREAM
|
||||
struct _RDPGFX_AVC420_BITMAP_STREAM
|
||||
{
|
||||
RDPGFX_H264_METABLOCK meta;
|
||||
UINT32 length;
|
||||
BYTE* data;
|
||||
};
|
||||
typedef struct _RDPGFX_H264_BITMAP_STREAM RDPGFX_H264_BITMAP_STREAM;
|
||||
typedef struct _RDPGFX_AVC420_BITMAP_STREAM RDPGFX_AVC420_BITMAP_STREAM;
|
||||
|
||||
struct _RDPGFX_AVC444_BITMAP_STREAM
|
||||
{
|
||||
UINT32 cbAvc420EncodedBitstream1;
|
||||
BYTE LC;
|
||||
RDPGFX_AVC420_BITMAP_STREAM bitstream[2];
|
||||
};
|
||||
typedef struct _RDPGFX_AVC444_BITMAP_STREAM RDPGFX_AVC444_BITMAP_STREAM;
|
||||
|
||||
|
||||
#endif /* FREERDP_CHANNEL_RDPGFX_H */
|
||||
|
||||
|
@ -29,8 +29,10 @@ typedef struct _H264_CONTEXT H264_CONTEXT;
|
||||
typedef BOOL (*pfnH264SubsystemInit)(H264_CONTEXT* h264);
|
||||
typedef void (*pfnH264SubsystemUninit)(H264_CONTEXT* h264);
|
||||
|
||||
typedef int (*pfnH264SubsystemDecompress)(H264_CONTEXT* h264, BYTE* pSrcData, UINT32 SrcSize);
|
||||
typedef int (*pfnH264SubsystemCompress)(H264_CONTEXT* h264, BYTE** ppDstData, UINT32* pDstSize);
|
||||
typedef int (*pfnH264SubsystemDecompress)(H264_CONTEXT* h264, BYTE* pSrcData,
|
||||
UINT32 SrcSize, UINT32 plane);
|
||||
typedef int (*pfnH264SubsystemCompress)(H264_CONTEXT* h264, BYTE** ppDstData,
|
||||
UINT32* pDstSize, UINT32 plane);
|
||||
|
||||
struct _H264_CONTEXT_SUBSYSTEM
|
||||
{
|
||||
@ -62,9 +64,14 @@ struct _H264_CONTEXT
|
||||
UINT32 QP;
|
||||
UINT32 NumberOfThreads;
|
||||
|
||||
int iStride[3];
|
||||
BYTE* pYUVData[3];
|
||||
UINT32 iStride[2][3];
|
||||
BYTE* pYUVData[2][3];
|
||||
|
||||
UINT32 iYUV444Size[3];
|
||||
UINT32 iYUV444Stride[3];
|
||||
BYTE* pYUV444Data[3];
|
||||
|
||||
UINT32 numSystemData;
|
||||
void* pSystemData;
|
||||
H264_CONTEXT_SUBSYSTEM* subsystem;
|
||||
};
|
||||
@ -73,12 +80,30 @@ struct _H264_CONTEXT
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
FREERDP_API int h264_compress(H264_CONTEXT* h264, BYTE* pSrcData, DWORD SrcFormat,
|
||||
int nSrcStep, int nSrcWidth, int nSrcHeight, BYTE** ppDstData, UINT32* pDstSize);
|
||||
FREERDP_API INT32 avc420_compress(H264_CONTEXT* h264, BYTE* pSrcData,
|
||||
DWORD SrcFormat, UINT32 nSrcStep,
|
||||
UINT32 nSrcWidth, UINT32 nSrcHeight,
|
||||
BYTE** ppDstData, UINT32* pDstSize);
|
||||
|
||||
FREERDP_API int h264_decompress(H264_CONTEXT* h264, BYTE* pSrcData, UINT32 SrcSize,
|
||||
BYTE** ppDstData, DWORD DstFormat, int nDstStep, int nDstWidth, int nDstHeight,
|
||||
RDPGFX_RECT16* regionRects, int numRegionRect);
|
||||
FREERDP_API INT32 avc420_decompress(H264_CONTEXT* h264, BYTE* pSrcData,
|
||||
UINT32 SrcSize, BYTE* pDstData,
|
||||
DWORD DstFormat, UINT32 nDstStep,
|
||||
UINT32 nDstWidth, UINT32 nDstHeight,
|
||||
RECTANGLE_16* regionRects, UINT32 numRegionRect);
|
||||
|
||||
FREERDP_API INT32 avc444_compress(H264_CONTEXT* h264, BYTE* pSrcData, DWORD SrcFormat,
|
||||
UINT32 nSrcStep, UINT32 nSrcWidth, UINT32 nSrcHeight,
|
||||
BYTE* op,
|
||||
BYTE** pDstData, UINT32* pDstSize,
|
||||
BYTE** pAuxDstData, UINT32* pAuxDstSize);
|
||||
|
||||
FREERDP_API INT32 avc444_decompress(H264_CONTEXT* h264, BYTE op,
|
||||
RECTANGLE_16* regionRects, UINT32 numRegionRect,
|
||||
BYTE* pSrcData, UINT32 SrcSize,
|
||||
RECTANGLE_16* auxRegionRects, UINT32 numAuxRegionRect,
|
||||
BYTE* pAuxSrcData, UINT32 AuxSrcSize,
|
||||
BYTE* pDstData, DWORD DstFormat,
|
||||
UINT32 nDstStep, UINT32 nDstWidth, UINT32 nDstHeight);
|
||||
|
||||
FREERDP_API BOOL h264_context_reset(H264_CONTEXT* h264, UINT32 width, UINT32 height);
|
||||
|
||||
|
@ -39,7 +39,8 @@
|
||||
#define FREERDP_CODEC_CLEARCODEC 0x00000010
|
||||
#define FREERDP_CODEC_ALPHACODEC 0x00000020
|
||||
#define FREERDP_CODEC_PROGRESSIVE 0x00000040
|
||||
#define FREERDP_CODEC_H264 0x00000080
|
||||
#define FREERDP_CODEC_AVC420 0x00000080
|
||||
#define FREERDP_CODEC_AVC444 0x00000100
|
||||
#define FREERDP_CODEC_ALL 0xFFFFFFFF
|
||||
|
||||
struct rdp_codecs
|
||||
|
@ -58,8 +58,8 @@ typedef INT32 pstatus_t; /* match IppStatus. */
|
||||
/* Structures compatible with IPP */
|
||||
typedef struct
|
||||
{
|
||||
INT32 width;
|
||||
INT32 height;
|
||||
UINT32 width;
|
||||
UINT32 height;
|
||||
} prim_size_t; /* like IppiSize */
|
||||
|
||||
/* Function prototypes for all of the supported primitives. */
|
||||
@ -74,7 +74,7 @@ typedef pstatus_t (*__copy_8u_t)(
|
||||
typedef pstatus_t (*__copy_8u_AC4r_t)(
|
||||
const BYTE *pSrc,
|
||||
INT32 srcStep, /* bytes */
|
||||
BYTE *pDst,
|
||||
BYTE *pDst,
|
||||
INT32 dstStep, /* bytes */
|
||||
INT32 width, INT32 height); /* pixels */
|
||||
typedef pstatus_t (*__set_8u_t)(
|
||||
@ -169,13 +169,31 @@ typedef pstatus_t (*__RGB565ToARGB_16u32u_C3C4_t)(
|
||||
UINT32 width, UINT32 height,
|
||||
BOOL alpha, BOOL invert);
|
||||
typedef pstatus_t (*__YUV420ToRGB_8u_P3AC4R_t)(
|
||||
const BYTE* pSrc[3], INT32 srcStep[3],
|
||||
BYTE* pDst, INT32 dstStep,
|
||||
const BYTE* pSrc[3], const UINT32 srcStep[3],
|
||||
BYTE* pDst, UINT32 dstStep,
|
||||
const prim_size_t* roi);
|
||||
typedef pstatus_t (*__YUV444ToRGB_8u_P3AC4R_t)(
|
||||
const BYTE* pSrc[3], const UINT32 srcStep[3],
|
||||
BYTE* pDst, UINT32 dstStep,
|
||||
const prim_size_t* roi);
|
||||
typedef pstatus_t (*__RGBToYUV420_8u_P3AC4R_t)(
|
||||
const BYTE* pSrc, INT32 srcStep,
|
||||
BYTE* pDst[3], INT32 dstStep[3],
|
||||
const BYTE* pSrc, UINT32 srcStep,
|
||||
BYTE* pDst[3], UINT32 dstStep[3],
|
||||
const prim_size_t* roi);
|
||||
typedef pstatus_t (*__RGBToYUV444_8u_P3AC4R_t)(
|
||||
const BYTE* pSrc, UINT32 srcStep,
|
||||
BYTE* pDst[3], UINT32 dstStep[3],
|
||||
const prim_size_t* roi);
|
||||
typedef pstatus_t (*__YUV420CombineToYUV444_t)(
|
||||
const BYTE* pMainSrc[3], const UINT32 srcMainStep[3],
|
||||
const BYTE* pAuxSrc[3], const UINT32 srcAuxStep[3],
|
||||
BYTE* pDst[3], const UINT32 dstStep[3],
|
||||
const prim_size_t* roi);
|
||||
typedef pstatus_t (*__YUV444SplitToYUV420_t)(
|
||||
const BYTE* pSrc[3], const UINT32 srcStep[3],
|
||||
BYTE* pMainDst[3], const UINT32 dstMainStep[3],
|
||||
BYTE* pAuxDst[3], const UINT32 srcAuxStep[3],
|
||||
const prim_size_t* roi);
|
||||
typedef pstatus_t (*__andC_32u_t)(
|
||||
const UINT32 *pSrc,
|
||||
UINT32 val,
|
||||
@ -224,6 +242,10 @@ typedef struct
|
||||
__RGB565ToARGB_16u32u_C3C4_t RGB565ToARGB_16u32u_C3C4;
|
||||
__YUV420ToRGB_8u_P3AC4R_t YUV420ToRGB_8u_P3AC4R;
|
||||
__RGBToYUV420_8u_P3AC4R_t RGBToYUV420_8u_P3AC4R;
|
||||
__RGBToYUV444_8u_P3AC4R_t RGBToYUV444_8u_P3AC4R;
|
||||
__YUV420CombineToYUV444_t YUV420CombineToYUV444;
|
||||
__YUV444SplitToYUV420_t YUV444SplitToYUV420;
|
||||
__YUV420ToRGB_8u_P3AC4R_t YUV444ToRGB_8u_P3AC4R;
|
||||
} primitives_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -234,7 +234,7 @@ endif()
|
||||
|
||||
if(WITH_SSE2)
|
||||
if(CMAKE_COMPILER_IS_GNUCC)
|
||||
set(OPTIMIZATION "${OPTIMIZATION} -msse2 -mssse3 -O2 -Wdeclaration-after-statement")
|
||||
set(OPTIMIZATION "${OPTIMIZATION} -msse2 -mssse3 -Wdeclaration-after-statement")
|
||||
endif()
|
||||
|
||||
if(MSVC)
|
||||
@ -251,12 +251,6 @@ if(DEFINED OPTIMIZATION)
|
||||
set_source_files_properties(${PRIMITIVES_OPT_SRCS} PROPERTIES COMPILE_FLAGS ${OPTIMIZATION})
|
||||
endif()
|
||||
|
||||
|
||||
# always compile with optimization
|
||||
if(CMAKE_COMPILER_IS_GNUCC)
|
||||
set_source_files_properties(${PRIMITIVES_SRCS} PROPERTIES COMPILE_FLAGS "-O2")
|
||||
endif()
|
||||
|
||||
set(PRIMITIVES_SRCS ${PRIMITIVES_SRCS} ${PRIMITIVES_OPT_SRCS})
|
||||
|
||||
freerdp_module_add(${PRIMITIVES_SRCS})
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -88,7 +88,7 @@ BOOL freerdp_client_codecs_prepare(rdpCodecs* codecs, UINT32 flags)
|
||||
}
|
||||
}
|
||||
|
||||
if ((flags & FREERDP_CODEC_H264) && !codecs->h264)
|
||||
if ((flags & (FREERDP_CODEC_AVC420 | FREERDP_CODEC_AVC444)) && !codecs->h264)
|
||||
{
|
||||
if (!(codecs->h264 = h264_context_new(FALSE)))
|
||||
{
|
||||
@ -161,7 +161,7 @@ BOOL freerdp_client_codecs_reset(rdpCodecs* codecs, UINT32 flags,
|
||||
}
|
||||
}
|
||||
|
||||
if (flags & FREERDP_CODEC_H264)
|
||||
if (flags & (FREERDP_CODEC_AVC420 | FREERDP_CODEC_AVC444))
|
||||
{
|
||||
if (codecs->h264)
|
||||
{
|
||||
@ -179,9 +179,7 @@ rdpCodecs* codecs_new(rdpContext* context)
|
||||
codecs = (rdpCodecs*) calloc(1, sizeof(rdpCodecs));
|
||||
|
||||
if (codecs)
|
||||
{
|
||||
codecs->context = context;
|
||||
}
|
||||
|
||||
return codecs;
|
||||
}
|
||||
|
@ -461,39 +461,38 @@ UINT gdi_SurfaceCommand_Planar(rdpGdi* gdi, RdpgfxClientContext* context, RDPGFX
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
UINT gdi_SurfaceCommand_H264(rdpGdi* gdi, RdpgfxClientContext* context, RDPGFX_SURFACE_COMMAND* cmd)
|
||||
static UINT gdi_SurfaceCommand_AVC420(rdpGdi* gdi, RdpgfxClientContext* context, RDPGFX_SURFACE_COMMAND* cmd)
|
||||
{
|
||||
int status;
|
||||
UINT32 i;
|
||||
BYTE* DstData = NULL;
|
||||
gdiGfxSurface* surface;
|
||||
RDPGFX_H264_METABLOCK* meta;
|
||||
RDPGFX_H264_BITMAP_STREAM* bs;
|
||||
RDPGFX_AVC420_BITMAP_STREAM* bs;
|
||||
|
||||
surface = (gdiGfxSurface*) context->GetSurfaceData(context, cmd->surfaceId);
|
||||
|
||||
if (!surface)
|
||||
return ERROR_INTERNAL_ERROR;
|
||||
|
||||
if (!freerdp_client_codecs_prepare(surface->codecs, FREERDP_CODEC_H264))
|
||||
if (!freerdp_client_codecs_prepare(surface->codecs, FREERDP_CODEC_AVC420))
|
||||
return ERROR_INTERNAL_ERROR;
|
||||
|
||||
bs = (RDPGFX_H264_BITMAP_STREAM*) cmd->extra;
|
||||
bs = (RDPGFX_AVC420_BITMAP_STREAM*) cmd->extra;
|
||||
|
||||
if (!bs)
|
||||
return ERROR_INTERNAL_ERROR;
|
||||
|
||||
meta = &(bs->meta);
|
||||
|
||||
DstData = surface->data;
|
||||
|
||||
status = h264_decompress(surface->codecs->h264, bs->data, bs->length, &DstData,
|
||||
PIXEL_FORMAT_XRGB32, surface->scanline, surface->width, surface->height,
|
||||
meta->regionRects, meta->numRegionRects);
|
||||
status = avc420_decompress(surface->codecs->h264, bs->data, bs->length,
|
||||
surface->data, PIXEL_FORMAT_XRGB32,
|
||||
surface->scanline, surface->width,
|
||||
surface->height, meta->regionRects,
|
||||
meta->numRegionRects);
|
||||
|
||||
if (status < 0)
|
||||
{
|
||||
WLog_WARN(TAG, "h264_decompress failure: %d, ignoring update.", status);
|
||||
WLog_WARN(TAG, "avc420_decompress failure: %d, ignoring update.", status);
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
@ -508,6 +507,77 @@ UINT gdi_SurfaceCommand_H264(rdpGdi* gdi, RdpgfxClientContext* context, RDPGFX_S
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function description
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
static UINT gdi_SurfaceCommand_AVC444(rdpGdi* gdi, RdpgfxClientContext* context, RDPGFX_SURFACE_COMMAND* cmd)
|
||||
{
|
||||
int status;
|
||||
UINT32 i;
|
||||
gdiGfxSurface* surface;
|
||||
RDPGFX_AVC444_BITMAP_STREAM* bs;
|
||||
RDPGFX_AVC420_BITMAP_STREAM* avc1;
|
||||
RDPGFX_H264_METABLOCK* meta1;
|
||||
RDPGFX_AVC420_BITMAP_STREAM* avc2;
|
||||
RDPGFX_H264_METABLOCK* meta2;
|
||||
RECTANGLE_16* regionRects = NULL;
|
||||
|
||||
surface = (gdiGfxSurface*) context->GetSurfaceData(context, cmd->surfaceId);
|
||||
|
||||
if (!surface)
|
||||
return ERROR_INTERNAL_ERROR;
|
||||
|
||||
if (!freerdp_client_codecs_prepare(surface->codecs, FREERDP_CODEC_AVC444))
|
||||
return ERROR_INTERNAL_ERROR;
|
||||
|
||||
bs = (RDPGFX_AVC444_BITMAP_STREAM*) cmd->extra;
|
||||
|
||||
if (!bs)
|
||||
return ERROR_INTERNAL_ERROR;
|
||||
|
||||
avc1 = &bs->bitstream[0];
|
||||
avc2 = &bs->bitstream[1];
|
||||
meta1 = &avc1->meta;
|
||||
meta2 = &avc2->meta;
|
||||
status = avc444_decompress(surface->codecs->h264, bs->LC,
|
||||
meta1->regionRects, meta1->numRegionRects,
|
||||
avc1->data, avc1->length,
|
||||
meta2->regionRects, meta2->numRegionRects,
|
||||
avc2->data, avc2->length,
|
||||
surface->data, PIXEL_FORMAT_XRGB32,
|
||||
surface->scanline, surface->width,
|
||||
surface->height);
|
||||
|
||||
if (status < 0)
|
||||
{
|
||||
WLog_WARN(TAG, "avc444_decompress failure: %d, ignoring update.", status);
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
for (i = 0; i < meta1->numRegionRects; 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]));
|
||||
}
|
||||
|
||||
if (!gdi->inGfxFrame)
|
||||
gdi_UpdateSurfaces(gdi);
|
||||
|
||||
free(regionRects);
|
||||
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function description
|
||||
*
|
||||
@ -677,8 +747,12 @@ UINT gdi_SurfaceCommand(RdpgfxClientContext* context, RDPGFX_SURFACE_COMMAND* cm
|
||||
status = gdi_SurfaceCommand_Planar(gdi, context, cmd);
|
||||
break;
|
||||
|
||||
case RDPGFX_CODECID_H264:
|
||||
status = gdi_SurfaceCommand_H264(gdi, context, cmd);
|
||||
case RDPGFX_CODECID_AVC420:
|
||||
status = gdi_SurfaceCommand_AVC420(gdi, context, cmd);
|
||||
break;
|
||||
|
||||
case RDPGFX_CODECID_AVC444:
|
||||
status = gdi_SurfaceCommand_AVC444(gdi, context, cmd);
|
||||
break;
|
||||
|
||||
case RDPGFX_CODECID_ALPHA:
|
||||
@ -807,7 +881,7 @@ UINT gdi_SolidFill(RdpgfxClientContext* context, RDPGFX_SOLID_FILL_PDU* solidFil
|
||||
UINT32 color;
|
||||
BYTE a, r, g, b;
|
||||
int nWidth, nHeight;
|
||||
RDPGFX_RECT16* rect;
|
||||
RECTANGLE_16* rect;
|
||||
gdiGfxSurface* surface;
|
||||
RECTANGLE_16 invalidRect;
|
||||
rdpGdi* gdi = (rdpGdi*) context->custom;
|
||||
@ -861,7 +935,7 @@ UINT gdi_SurfaceToSurface(RdpgfxClientContext* context, RDPGFX_SURFACE_TO_SURFAC
|
||||
UINT16 index;
|
||||
BOOL sameSurface;
|
||||
int nWidth, nHeight;
|
||||
RDPGFX_RECT16* rectSrc;
|
||||
RECTANGLE_16* rectSrc;
|
||||
RDPGFX_POINT16* destPt;
|
||||
RECTANGLE_16 invalidRect;
|
||||
gdiGfxSurface* surfaceSrc;
|
||||
@ -922,7 +996,7 @@ UINT gdi_SurfaceToSurface(RdpgfxClientContext* context, RDPGFX_SURFACE_TO_SURFAC
|
||||
*/
|
||||
UINT gdi_SurfaceToCache(RdpgfxClientContext* context, RDPGFX_SURFACE_TO_CACHE_PDU* surfaceToCache)
|
||||
{
|
||||
RDPGFX_RECT16* rect;
|
||||
RECTANGLE_16* rect;
|
||||
gdiGfxSurface* surface;
|
||||
gdiGfxCacheEntry* cacheEntry;
|
||||
rdpGdi* gdi = (rdpGdi*) context->custom;
|
||||
|
@ -26,43 +26,368 @@
|
||||
|
||||
#include "prim_YUV.h"
|
||||
|
||||
static INLINE BYTE CLIP(INT32 X)
|
||||
{
|
||||
if (X > 255L)
|
||||
return 255L;
|
||||
if (X < 0L)
|
||||
return 0L;
|
||||
return X;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief general_YUV420CombineToYUV444
|
||||
*
|
||||
* @param pMainSrc Pointer to luma YUV420 data
|
||||
* @param srcMainStep Step width in luma YUV420 data
|
||||
* @param pAuxSrc Pointer to chroma YUV420 data
|
||||
* @param srcAuxStep Step width in chroma YUV420 data
|
||||
* @param pDst Pointer to YUV444 data
|
||||
* @param dstStep Step width in YUV444 data
|
||||
* @param roi Region of source to combine in destination.
|
||||
*
|
||||
* @return PRIMITIVES_SUCCESS on success, an error code otherwise.
|
||||
*/
|
||||
static pstatus_t general_YUV420CombineToYUV444(
|
||||
const BYTE* pMainSrc[3], const UINT32 srcMainStep[3],
|
||||
const BYTE* pAuxSrc[3], const UINT32 srcAuxStep[3],
|
||||
BYTE* pDst[3], const UINT32 dstStep[3],
|
||||
const prim_size_t* roi)
|
||||
{
|
||||
const UINT32 mod = 16;
|
||||
UINT32 uY = 0;
|
||||
UINT32 vY = 0;
|
||||
UINT32 x, y;
|
||||
UINT32 nWidth, nHeight;
|
||||
UINT32 halfWidth, halfHeight;
|
||||
const UINT32 oddY = 1;
|
||||
const UINT32 evenY = 0;
|
||||
const UINT32 oddX = 1;
|
||||
const UINT32 evenX = 0;
|
||||
|
||||
/* The auxilary frame is aligned to multiples of 16x16.
|
||||
* We need the padded height for B4 and B5 conversion. */
|
||||
const UINT32 padHeigth = roi->height + 16 - roi->height % 16;
|
||||
|
||||
nWidth = roi->width;
|
||||
nHeight = roi->height;
|
||||
halfWidth = (nWidth ) / 2;
|
||||
halfHeight = (nHeight) / 2;
|
||||
|
||||
if (pMainSrc)
|
||||
{
|
||||
/* Y data is already here... */
|
||||
/* B1 */
|
||||
for (y=0; y<nHeight; y++)
|
||||
{
|
||||
const BYTE* Ym = pMainSrc[0] + srcMainStep[0] * y;
|
||||
BYTE* pY = pDst[0] + dstStep[0] * y;
|
||||
|
||||
memcpy(pY, Ym, nWidth);
|
||||
}
|
||||
|
||||
/* The first half of U, V are already here part of this frame. */
|
||||
/* B2 and B3 */
|
||||
for (y=0; y<halfHeight; y++)
|
||||
{
|
||||
const UINT32 val2y = (2 * y + evenY);
|
||||
const UINT32 val2y1 = val2y + oddY;
|
||||
const BYTE* Um = pMainSrc[1] + srcMainStep[1] * y;
|
||||
const BYTE* Vm = pMainSrc[2] + srcMainStep[2] * y;
|
||||
BYTE* pU = pDst[1] + dstStep[1] * val2y;
|
||||
BYTE* pV = pDst[2] + dstStep[2] * val2y;
|
||||
BYTE* pU1 = pDst[1] + dstStep[1] * val2y1;
|
||||
BYTE* pV1 = pDst[2] + dstStep[2] * val2y1;
|
||||
|
||||
for (x=0; x<halfWidth; x++)
|
||||
{
|
||||
const UINT32 val2x = 2*x + evenX;
|
||||
const UINT32 val2x1 = val2x+oddX;
|
||||
|
||||
pU[val2x] = Um[x];
|
||||
pV[val2x] = Vm[x];
|
||||
pU[val2x1] = Um[x];
|
||||
pV[val2x1] = Vm[x];
|
||||
pU1[val2x] = Um[x];
|
||||
pV1[val2x] = Vm[x];
|
||||
pU1[val2x1] = Um[x];
|
||||
pV1[val2x1] = Vm[x];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!pAuxSrc)
|
||||
return PRIMITIVES_SUCCESS;
|
||||
|
||||
/* The second half of U and V is a bit more tricky... */
|
||||
/* B4 and B5 */
|
||||
for (y=0; y<padHeigth; y++)
|
||||
{
|
||||
const BYTE* Ya = pAuxSrc[0] + srcAuxStep[0] * y;
|
||||
BYTE* pX;
|
||||
|
||||
if ((y) % mod < (mod + 1)/2)
|
||||
{
|
||||
const UINT32 pos = (2 * uY++ + oddY);
|
||||
if (pos >= nHeight)
|
||||
continue;
|
||||
pX = pDst[1] + dstStep[1] * pos;
|
||||
}
|
||||
else
|
||||
{
|
||||
const UINT32 pos = (2 * vY++ + oddY);
|
||||
if (pos >= nHeight)
|
||||
continue;
|
||||
pX = pDst[2] + dstStep[2] * pos;
|
||||
}
|
||||
|
||||
memcpy(pX, Ya, nWidth);
|
||||
}
|
||||
|
||||
/* B6 and B7 */
|
||||
for (y=0; y<halfHeight; y++)
|
||||
{
|
||||
const UINT32 val2y = (y * 2 + evenY);
|
||||
const BYTE* Ua = pAuxSrc[1] + srcAuxStep[1] * y;
|
||||
const BYTE* Va = pAuxSrc[2] + srcAuxStep[2] * y;
|
||||
BYTE* pU = pDst[1] + dstStep[1] * val2y;
|
||||
BYTE* pV = pDst[2] + dstStep[2] * val2y;
|
||||
|
||||
for (x=0; x<halfWidth; x++)
|
||||
{
|
||||
const UINT32 val2x1 = (x * 2 + oddX);
|
||||
pU[val2x1] = Ua[x];
|
||||
pV[val2x1] = Va[x];
|
||||
}
|
||||
}
|
||||
|
||||
/* Filter */
|
||||
for (y=0; y<halfHeight; y++)
|
||||
{
|
||||
const UINT32 val2y = (y * 2 + evenY);
|
||||
const UINT32 val2y1 = val2y + oddY;
|
||||
|
||||
BYTE* pU1 = pDst[1] + dstStep[1] * val2y1;
|
||||
BYTE* pV1 = pDst[2] + dstStep[2] * val2y1;
|
||||
BYTE* pU = pDst[1] + dstStep[1] * val2y;
|
||||
BYTE* pV = pDst[2] + dstStep[2] * val2y;
|
||||
|
||||
if (val2y1 > nHeight)
|
||||
continue;
|
||||
|
||||
for (x=0; x<halfWidth; x++)
|
||||
{
|
||||
const UINT32 val2x = (x * 2);
|
||||
const UINT32 val2x1 = val2x + 1;
|
||||
const INT32 up = pU[val2x] * 4;
|
||||
const INT32 vp = pV[val2x] * 4;
|
||||
INT32 u2020;
|
||||
INT32 v2020;
|
||||
|
||||
if (val2x1 > nWidth)
|
||||
continue;
|
||||
|
||||
u2020 = up - pU[val2x1] - pU1[val2x] - pU1[val2x1];
|
||||
v2020 = vp - pV[val2x1] - pV1[val2x] - pV1[val2x1];
|
||||
|
||||
pU[val2x] = CLIP(u2020);
|
||||
pV[val2x] = CLIP(v2020);
|
||||
}
|
||||
}
|
||||
|
||||
return PRIMITIVES_SUCCESS;
|
||||
}
|
||||
|
||||
static pstatus_t general_YUV444SplitToYUV420(
|
||||
const BYTE* pSrc[3], const UINT32 srcStep[3],
|
||||
BYTE* pMainDst[3], const UINT32 dstMainStep[3],
|
||||
BYTE* pAuxDst[3], const UINT32 dstAuxStep[3],
|
||||
const prim_size_t* roi)
|
||||
{
|
||||
UINT32 x, y, uY = 0, vY = 0;
|
||||
UINT32 halfWidth, halfHeight;
|
||||
/* The auxilary frame is aligned to multiples of 16x16.
|
||||
* We need the padded height for B4 and B5 conversion. */
|
||||
const UINT32 padHeigth = roi->height + 16 - roi->height % 16;
|
||||
|
||||
halfWidth = (roi->width + 1) / 2;
|
||||
halfHeight = (roi->height + 1) / 2;
|
||||
|
||||
/* B1 */
|
||||
for (y=0; y<roi->height; y++)
|
||||
{
|
||||
const BYTE* pSrcY = pSrc[0] + y * srcStep[0];
|
||||
BYTE* pY = pMainDst[0] + y * dstMainStep[0];
|
||||
memcpy(pY, pSrcY, roi->width);
|
||||
}
|
||||
|
||||
/* B2 and B3 */
|
||||
for (y=0; y<halfHeight; y++)
|
||||
{
|
||||
const BYTE* pSrcU = pSrc[1] + 2 * y * srcStep[1];
|
||||
const BYTE* pSrcV = pSrc[2] + 2 * y * srcStep[2];
|
||||
const BYTE* pSrcU1 = pSrc[1] + (2 * y + 1) * srcStep[1];
|
||||
const BYTE* pSrcV1 = pSrc[2] + (2 * y + 1) * srcStep[2];
|
||||
BYTE* pU = pMainDst[1] + y * dstMainStep[1];
|
||||
BYTE* pV = pMainDst[2] + y * dstMainStep[2];
|
||||
|
||||
for (x=0; x<halfWidth; x++)
|
||||
{
|
||||
/* Filter */
|
||||
const INT32 u = pSrcU[2*x] + pSrcU[2*x+1] + pSrcU1[2*x]
|
||||
+ pSrcU1[2*x+1];
|
||||
const INT32 v = pSrcV[2*x] + pSrcV[2*x+1] + pSrcV1[2*x]
|
||||
+ pSrcV1[2*x+1];
|
||||
pU[x] = CLIP(u / 4L);
|
||||
pV[x] = CLIP(v / 4L);
|
||||
}
|
||||
}
|
||||
|
||||
/* B4 and B5 */
|
||||
for (y=0; y<padHeigth; y++)
|
||||
{
|
||||
BYTE* pY = pAuxDst[0] + y * dstAuxStep[0];
|
||||
|
||||
if (y % 16 < 8)
|
||||
{
|
||||
const UINT32 pos = (2 * uY++ + 1);
|
||||
const BYTE* pSrcU = pSrc[1] + pos * srcStep[1];
|
||||
if (pos >= roi->height)
|
||||
continue;
|
||||
memcpy(pY, pSrcU, roi->width);
|
||||
}
|
||||
else
|
||||
{
|
||||
const UINT32 pos = (2 * vY++ + 1);
|
||||
const BYTE* pSrcV = pSrc[2] + pos * srcStep[2];
|
||||
if (pos >= roi->height)
|
||||
continue;
|
||||
memcpy(pY, pSrcV, roi->width);
|
||||
}
|
||||
}
|
||||
|
||||
/* B6 and B7 */
|
||||
for (y=0; y<halfHeight; y++)
|
||||
{
|
||||
const BYTE* pSrcU = pSrc[1] + 2 * y * srcStep[1];
|
||||
const BYTE* pSrcV = pSrc[2] + 2 * y * srcStep[2];
|
||||
BYTE* pU = pAuxDst[1] + y * dstAuxStep[1];
|
||||
BYTE* pV = pAuxDst[2] + y * dstAuxStep[2];
|
||||
|
||||
for (x=0; x<halfWidth; x++)
|
||||
{
|
||||
pU[x] = pSrcU[2*x+1];
|
||||
pV[x] = pSrcV[2*x+1];
|
||||
}
|
||||
}
|
||||
|
||||
return PRIMITIVES_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* | R | ( | 256 0 403 | | Y | )
|
||||
* | G | = ( | 256 -48 -120 | | U - 128 | ) >> 8
|
||||
* | B | ( | 256 475 0 | | V - 128 | )
|
||||
*/
|
||||
static INLINE INT32 C(INT32 Y)
|
||||
{
|
||||
return (Y) - 0L;
|
||||
}
|
||||
|
||||
static INLINE INT32 D(INT32 U)
|
||||
{
|
||||
return (U) - 128L;
|
||||
}
|
||||
|
||||
static INLINE INT32 E(INT32 V)
|
||||
{
|
||||
return (V) - 128L;
|
||||
}
|
||||
|
||||
static INLINE BYTE YUV2R(INT32 Y, INT32 U, INT32 V)
|
||||
{
|
||||
const INT32 r = ( 256L * C(Y) + 0L * D(U) + 403L * E(V));
|
||||
const INT32 r8 = r >> 8L;
|
||||
return CLIP(r8);
|
||||
}
|
||||
|
||||
static INLINE BYTE YUV2G(INT32 Y, INT32 U, INT32 V)
|
||||
{
|
||||
const INT32 g = ( 256L * C(Y) - 48L * D(U) - 120L * E(V));
|
||||
const INT32 g8 = g >> 8L;
|
||||
return CLIP(g8);
|
||||
}
|
||||
|
||||
static INLINE BYTE YUV2B(INT32 Y, INT32 U, INT32 V)
|
||||
{
|
||||
const INT32 b = ( 256L * C(Y) + 475L * D(U) + 0L * E(V));
|
||||
const INT32 b8 = b >> 8L;
|
||||
return CLIP(b8);
|
||||
}
|
||||
|
||||
static pstatus_t general_YUV444ToRGB_8u_P3AC4R(
|
||||
const BYTE* pSrc[3], const UINT32 srcStep[3],
|
||||
BYTE* pDst, UINT32 dstStep, const prim_size_t* roi)
|
||||
{
|
||||
UINT32 x, y;
|
||||
UINT32 nWidth, nHeight;
|
||||
|
||||
nWidth = roi->width;
|
||||
nHeight = roi->height;
|
||||
|
||||
for (y = 0; y < nHeight; y++)
|
||||
{
|
||||
const BYTE* pY = pSrc[0] + y * srcStep[0];
|
||||
const BYTE* pU = pSrc[1] + y * srcStep[1];
|
||||
const BYTE* pV = pSrc[2] + y * srcStep[2];
|
||||
BYTE* pRGB = pDst + y * dstStep;
|
||||
|
||||
for (x = 0; x < nWidth; x++)
|
||||
{
|
||||
const BYTE Y = pY[x];
|
||||
const INT32 U = pU[x];
|
||||
const INT32 V = pV[x];
|
||||
|
||||
pRGB[4*x+0] = YUV2B(Y, U, V);
|
||||
pRGB[4*x+1] = YUV2G(Y, U, V);
|
||||
pRGB[4*x+2] = YUV2R(Y, U, V);
|
||||
pRGB[4*x+3] = 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
return PRIMITIVES_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* | R | ( | 256 0 403 | | Y | )
|
||||
* | G | = ( | 256 -48 -120 | | U - 128 | ) >> 8
|
||||
* | B | ( | 256 475 0 | | V - 128 | )
|
||||
*
|
||||
* | Y | ( | 54 183 18 | | R | ) | 0 |
|
||||
* | U | = ( | -29 -99 128 | | G | ) >> 8 + | 128 |
|
||||
* | V | ( | 128 -116 -12 | | B | ) | 128 |
|
||||
*/
|
||||
|
||||
pstatus_t general_YUV420ToRGB_8u_P3AC4R(const BYTE* pSrc[3], int srcStep[3],
|
||||
BYTE* pDst, int dstStep, const prim_size_t* roi)
|
||||
static pstatus_t general_YUV420ToRGB_8u_P3AC4R(
|
||||
const BYTE* pSrc[3], const UINT32 srcStep[3],
|
||||
BYTE* pDst, UINT32 dstStep, const prim_size_t* roi)
|
||||
{
|
||||
int x, y;
|
||||
int dstPad;
|
||||
int srcPad[3];
|
||||
UINT32 x, y;
|
||||
UINT32 dstPad;
|
||||
UINT32 srcPad[3];
|
||||
BYTE Y, U, V;
|
||||
int halfWidth;
|
||||
int halfHeight;
|
||||
UINT32 halfWidth;
|
||||
UINT32 halfHeight;
|
||||
const BYTE* pY;
|
||||
const BYTE* pU;
|
||||
const BYTE* pV;
|
||||
int R, G, B;
|
||||
int Yp, Up, Vp;
|
||||
int Up48, Up475;
|
||||
int Vp403, Vp120;
|
||||
BYTE* pRGB = pDst;
|
||||
int nWidth, nHeight;
|
||||
int lastRow, lastCol;
|
||||
UINT32 nWidth, nHeight;
|
||||
UINT32 lastRow, lastCol;
|
||||
|
||||
pY = pSrc[0];
|
||||
pU = pSrc[1];
|
||||
pV = pSrc[2];
|
||||
|
||||
|
||||
lastCol = roi->width & 0x01;
|
||||
lastRow = roi->height & 0x01;
|
||||
|
||||
|
||||
nWidth = (roi->width + 1) & ~0x0001;
|
||||
nHeight = (roi->height + 1) & ~0x0001;
|
||||
|
||||
@ -88,73 +413,22 @@ pstatus_t general_YUV420ToRGB_8u_P3AC4R(const BYTE* pSrc[3], int srcStep[3],
|
||||
U = *pU++;
|
||||
V = *pV++;
|
||||
|
||||
Up = U - 128;
|
||||
Vp = V - 128;
|
||||
|
||||
Up48 = 48 * Up;
|
||||
Up475 = 475 * Up;
|
||||
|
||||
Vp403 = Vp * 403;
|
||||
Vp120 = Vp * 120;
|
||||
|
||||
/* 1st pixel */
|
||||
|
||||
Y = *pY++;
|
||||
Yp = Y << 8;
|
||||
|
||||
R = (Yp + Vp403) >> 8;
|
||||
G = (Yp - Up48 - Vp120) >> 8;
|
||||
B = (Yp + Up475) >> 8;
|
||||
|
||||
if (R < 0)
|
||||
R = 0;
|
||||
else if (R > 255)
|
||||
R = 255;
|
||||
|
||||
if (G < 0)
|
||||
G = 0;
|
||||
else if (G > 255)
|
||||
G = 255;
|
||||
|
||||
if (B < 0)
|
||||
B = 0;
|
||||
else if (B > 255)
|
||||
B = 255;
|
||||
|
||||
*pRGB++ = (BYTE) B;
|
||||
*pRGB++ = (BYTE) G;
|
||||
*pRGB++ = (BYTE) R;
|
||||
*pRGB++ = YUV2B(Y, U, V);
|
||||
*pRGB++ = YUV2G(Y, U, V);
|
||||
*pRGB++ = YUV2R(Y, U, V);
|
||||
*pRGB++ = 0xFF;
|
||||
|
||||
/* 2nd pixel */
|
||||
|
||||
if (!(lastCol & 0x02))
|
||||
{
|
||||
Y = *pY++;
|
||||
Yp = Y << 8;
|
||||
|
||||
R = (Yp + Vp403) >> 8;
|
||||
G = (Yp - Up48 - Vp120) >> 8;
|
||||
B = (Yp + Up475) >> 8;
|
||||
|
||||
if (R < 0)
|
||||
R = 0;
|
||||
else if (R > 255)
|
||||
R = 255;
|
||||
|
||||
if (G < 0)
|
||||
G = 0;
|
||||
else if (G > 255)
|
||||
G = 255;
|
||||
|
||||
if (B < 0)
|
||||
B = 0;
|
||||
else if (B > 255)
|
||||
B = 255;
|
||||
|
||||
*pRGB++ = (BYTE) B;
|
||||
*pRGB++ = (BYTE) G;
|
||||
*pRGB++ = (BYTE) R;
|
||||
*pRGB++ = YUV2B(Y, U, V);
|
||||
*pRGB++ = YUV2G(Y, U, V);
|
||||
*pRGB++ = YUV2R(Y, U, V);
|
||||
*pRGB++ = 0xFF;
|
||||
}
|
||||
else
|
||||
@ -170,6 +444,9 @@ pstatus_t general_YUV420ToRGB_8u_P3AC4R(const BYTE* pSrc[3], int srcStep[3],
|
||||
pV -= halfWidth;
|
||||
pRGB += dstPad;
|
||||
|
||||
if (lastRow & 0x02)
|
||||
break;
|
||||
|
||||
for (x = 0; x < halfWidth; )
|
||||
{
|
||||
if (++x == halfWidth)
|
||||
@ -178,73 +455,22 @@ pstatus_t general_YUV420ToRGB_8u_P3AC4R(const BYTE* pSrc[3], int srcStep[3],
|
||||
U = *pU++;
|
||||
V = *pV++;
|
||||
|
||||
Up = U - 128;
|
||||
Vp = V - 128;
|
||||
|
||||
Up48 = 48 * Up;
|
||||
Up475 = 475 * Up;
|
||||
|
||||
Vp403 = Vp * 403;
|
||||
Vp120 = Vp * 120;
|
||||
|
||||
/* 3rd pixel */
|
||||
|
||||
Y = *pY++;
|
||||
Yp = Y << 8;
|
||||
|
||||
R = (Yp + Vp403) >> 8;
|
||||
G = (Yp - Up48 - Vp120) >> 8;
|
||||
B = (Yp + Up475) >> 8;
|
||||
|
||||
if (R < 0)
|
||||
R = 0;
|
||||
else if (R > 255)
|
||||
R = 255;
|
||||
|
||||
if (G < 0)
|
||||
G = 0;
|
||||
else if (G > 255)
|
||||
G = 255;
|
||||
|
||||
if (B < 0)
|
||||
B = 0;
|
||||
else if (B > 255)
|
||||
B = 255;
|
||||
|
||||
*pRGB++ = (BYTE) B;
|
||||
*pRGB++ = (BYTE) G;
|
||||
*pRGB++ = (BYTE) R;
|
||||
*pRGB++ = YUV2B(Y, U, V);
|
||||
*pRGB++ = YUV2G(Y, U, V);
|
||||
*pRGB++ = YUV2R(Y, U, V);
|
||||
*pRGB++ = 0xFF;
|
||||
|
||||
/* 4th pixel */
|
||||
|
||||
if (!(lastCol & 0x02))
|
||||
{
|
||||
Y = *pY++;
|
||||
Yp = Y << 8;
|
||||
|
||||
R = (Yp + Vp403) >> 8;
|
||||
G = (Yp - Up48 - Vp120) >> 8;
|
||||
B = (Yp + Up475) >> 8;
|
||||
|
||||
if (R < 0)
|
||||
R = 0;
|
||||
else if (R > 255)
|
||||
R = 255;
|
||||
|
||||
if (G < 0)
|
||||
G = 0;
|
||||
else if (G > 255)
|
||||
G = 255;
|
||||
|
||||
if (B < 0)
|
||||
B = 0;
|
||||
else if (B > 255)
|
||||
B = 255;
|
||||
|
||||
*pRGB++ = (BYTE) B;
|
||||
*pRGB++ = (BYTE) G;
|
||||
*pRGB++ = (BYTE) R;
|
||||
*pRGB++ = YUV2B(Y, U, V);
|
||||
*pRGB++ = YUV2G(Y, U, V);
|
||||
*pRGB++ = YUV2R(Y, U, V);
|
||||
*pRGB++ = 0xFF;
|
||||
}
|
||||
else
|
||||
@ -264,102 +490,142 @@ pstatus_t general_YUV420ToRGB_8u_P3AC4R(const BYTE* pSrc[3], int srcStep[3],
|
||||
return PRIMITIVES_SUCCESS;
|
||||
}
|
||||
|
||||
pstatus_t general_RGBToYUV420_8u_P3AC4R(const BYTE* pSrc, INT32 srcStep,
|
||||
BYTE* pDst[3], INT32 dstStep[3], const prim_size_t* roi)
|
||||
/**
|
||||
* | Y | ( | 54 183 18 | | R | ) | 0 |
|
||||
* | U | = ( | -29 -99 128 | | G | ) >> 8 + | 128 |
|
||||
* | V | ( | 128 -116 -12 | | B | ) | 128 |
|
||||
*/
|
||||
static INLINE BYTE RGB2Y(INT32 R, INT32 G, INT32 B)
|
||||
{
|
||||
int x, y;
|
||||
int dstPad[3];
|
||||
int halfWidth;
|
||||
int halfHeight;
|
||||
BYTE* pY;
|
||||
BYTE* pU;
|
||||
BYTE* pV;
|
||||
int Y, U, V;
|
||||
int R, G, B;
|
||||
int Ra, Ga, Ba;
|
||||
const BYTE* pRGB;
|
||||
int nWidth, nHeight;
|
||||
const INT32 y = ( 54L * (R) + 183L * (G) + 18L * (B));
|
||||
const INT32 y8 = (y >> 8L);
|
||||
|
||||
pU = pDst[1];
|
||||
pV = pDst[2];
|
||||
return CLIP(y8);
|
||||
}
|
||||
|
||||
nWidth = (roi->width + 1) & ~0x0001;
|
||||
nHeight = (roi->height + 1) & ~0x0001;
|
||||
static INLINE BYTE RGB2U(INT32 R, INT32 G, INT32 B)
|
||||
{
|
||||
const INT32 u = ( -29L * (R) - 99L * (G) + 128L * (B));
|
||||
const INT32 u8 = (u >> 8L) + 128L;
|
||||
|
||||
halfWidth = nWidth / 2;
|
||||
halfHeight = nHeight / 2;
|
||||
return CLIP(u8);
|
||||
}
|
||||
|
||||
dstPad[0] = (dstStep[0] - nWidth);
|
||||
dstPad[1] = (dstStep[1] - halfWidth);
|
||||
dstPad[2] = (dstStep[2] - halfWidth);
|
||||
static INLINE BYTE RGB2V(INT32 R, INT32 G, INT32 B)
|
||||
{
|
||||
const INT32 v = ( 128L * (R) - 116L * (G) - 12L * (B));
|
||||
const INT32 v8 = (v >> 8L) + 128L;
|
||||
|
||||
return CLIP(v8);
|
||||
}
|
||||
|
||||
static pstatus_t general_RGBToYUV444_8u_P3AC4R(
|
||||
const BYTE* pSrc, const UINT32 srcStep,
|
||||
BYTE* pDst[3], UINT32 dstStep[3], const prim_size_t* roi)
|
||||
{
|
||||
UINT32 x, y;
|
||||
UINT32 nWidth, nHeight;
|
||||
|
||||
nWidth = roi->width;
|
||||
nHeight = roi->height;
|
||||
|
||||
for (y=0; y<nHeight; y++)
|
||||
{
|
||||
const BYTE* pRGB = pSrc + y * srcStep;
|
||||
|
||||
BYTE* pY = pDst[0] + y * dstStep[0];
|
||||
BYTE* pU = pDst[1] + y * dstStep[1];
|
||||
BYTE* pV = pDst[2] + y * dstStep[2];
|
||||
|
||||
for (x=0; x<nWidth; x++)
|
||||
{
|
||||
const BYTE B = pRGB[4*x+0];
|
||||
const BYTE G = pRGB[4*x+1];
|
||||
const BYTE R = pRGB[4*x+2];
|
||||
|
||||
pY[x] = RGB2Y(R, G, B);
|
||||
pU[x] = RGB2U(R, G, B);
|
||||
pV[x] = RGB2V(R, G, B);
|
||||
}
|
||||
}
|
||||
|
||||
return PRIMITIVES_SUCCESS;
|
||||
}
|
||||
|
||||
static pstatus_t general_RGBToYUV420_8u_P3AC4R(
|
||||
const BYTE* pSrc, UINT32 srcStep,
|
||||
BYTE* pDst[3], UINT32 dstStep[3], const prim_size_t* roi)
|
||||
{
|
||||
UINT32 x, y;
|
||||
UINT32 halfWidth;
|
||||
UINT32 halfHeight;
|
||||
UINT32 nWidth, nHeight;
|
||||
|
||||
nWidth = roi->width + roi->width % 2;
|
||||
nHeight = roi->height + roi->height % 2;
|
||||
|
||||
halfWidth = (nWidth + nWidth % 2) / 2;
|
||||
halfHeight = (nHeight + nHeight % 2) / 2;
|
||||
|
||||
for (y = 0; y < halfHeight; y++)
|
||||
{
|
||||
const UINT32 val2y = (y * 2);
|
||||
const UINT32 val2y1 = val2y + 1;
|
||||
const BYTE* pRGB = pSrc + val2y * srcStep;
|
||||
const BYTE* pRGB1 = pSrc + val2y1 * srcStep;
|
||||
|
||||
BYTE* pY = pDst[0] + val2y * dstStep[0];
|
||||
BYTE* pY1 = pDst[0] + val2y1 * dstStep[0];
|
||||
BYTE* pU = pDst[1] + y * dstStep[1];
|
||||
BYTE* pV = pDst[2] + y * dstStep[2];
|
||||
|
||||
for (x = 0; x < halfWidth; x++)
|
||||
{
|
||||
/* 1st pixel */
|
||||
pRGB = pSrc + y * 2 * srcStep + x * 2 * 4;
|
||||
pY = pDst[0] + y * 2 * dstStep[0] + x * 2;
|
||||
Ba = B = pRGB[0];
|
||||
Ga = G = pRGB[1];
|
||||
Ra = R = pRGB[2];
|
||||
Y = (54 * R + 183 * G + 18 * B) >> 8;
|
||||
pY[0] = (BYTE) Y;
|
||||
INT32 R, G, B;
|
||||
INT32 Ra, Ga, Ba;
|
||||
const UINT32 val2x = (x * 2);
|
||||
const UINT32 val2x1 = val2x + 1;
|
||||
|
||||
if (x * 2 + 1 < roi->width)
|
||||
/* 1st pixel */
|
||||
Ba = B = pRGB[val2x * 4 + 0];
|
||||
Ga = G = pRGB[val2x * 4 + 1];
|
||||
Ra = R = pRGB[val2x * 4 + 2];
|
||||
pY[val2x] = RGB2Y(R, G, B);
|
||||
|
||||
if (val2x1 < nWidth)
|
||||
{
|
||||
/* 2nd pixel */
|
||||
Ba += B = pRGB[4];
|
||||
Ga += G = pRGB[5];
|
||||
Ra += R = pRGB[6];
|
||||
Y = (54 * R + 183 * G + 18 * B) >> 8;
|
||||
pY[1] = (BYTE) Y;
|
||||
Ba += B = pRGB[val2x * 4 + 4];
|
||||
Ga += G = pRGB[val2x * 4 + 5];
|
||||
Ra += R = pRGB[val2x * 4 + 6];
|
||||
pY[val2x1] = RGB2Y(R, G, B);
|
||||
}
|
||||
|
||||
if (y * 2 + 1 < roi->height)
|
||||
if (val2y1 < nHeight)
|
||||
{
|
||||
/* 3rd pixel */
|
||||
pRGB += srcStep;
|
||||
pY += dstStep[0];
|
||||
Ba += B = pRGB[0];
|
||||
Ga += G = pRGB[1];
|
||||
Ra += R = pRGB[2];
|
||||
Y = (54 * R + 183 * G + 18 * B) >> 8;
|
||||
pY[0] = (BYTE) Y;
|
||||
Ba += B = pRGB1[val2x * 4 + 0];
|
||||
Ga += G = pRGB1[val2x * 4 + 1];
|
||||
Ra += R = pRGB1[val2x * 4 + 2];
|
||||
pY1[val2x] = RGB2Y(R, G, B);
|
||||
|
||||
if (x * 2 + 1 < roi->width)
|
||||
if (val2x1 < nWidth)
|
||||
{
|
||||
/* 4th pixel */
|
||||
Ba += B = pRGB[4];
|
||||
Ga += G = pRGB[5];
|
||||
Ra += R = pRGB[6];
|
||||
Y = (54 * R + 183 * G + 18 * B) >> 8;
|
||||
pY[1] = (BYTE) Y;
|
||||
Ba += B = pRGB1[val2x * 4 + 4];
|
||||
Ga += G = pRGB1[val2x * 4 + 5];
|
||||
Ra += R = pRGB1[val2x * 4 + 6];
|
||||
pY1[val2x1] = RGB2Y(R, G, B);
|
||||
}
|
||||
}
|
||||
|
||||
/* U */
|
||||
Ba >>= 2;
|
||||
Ga >>= 2;
|
||||
Ra >>= 2;
|
||||
U = ((-29 * Ra - 99 * Ga + 128 * Ba) >> 8) + 128;
|
||||
if (U < 0)
|
||||
U = 0;
|
||||
else if (U > 255)
|
||||
U = 255;
|
||||
*pU++ = (BYTE) U;
|
||||
|
||||
/* V */
|
||||
V = ((128 * Ra - 116 * Ga - 12 * Ba) >> 8) + 128;
|
||||
if (V < 0)
|
||||
V = 0;
|
||||
else if (V > 255)
|
||||
V = 255;
|
||||
*pV++ = (BYTE) V;
|
||||
pU[x] = RGB2U(Ra, Ga, Ba);
|
||||
pV[x] = RGB2V(Ra, Ga, Ba);
|
||||
}
|
||||
|
||||
pU += dstPad[1];
|
||||
pV += dstPad[2];
|
||||
}
|
||||
|
||||
return PRIMITIVES_SUCCESS;
|
||||
@ -368,8 +634,12 @@ pstatus_t general_RGBToYUV420_8u_P3AC4R(const BYTE* pSrc, INT32 srcStep,
|
||||
void primitives_init_YUV(primitives_t* prims)
|
||||
{
|
||||
prims->YUV420ToRGB_8u_P3AC4R = general_YUV420ToRGB_8u_P3AC4R;
|
||||
prims->YUV444ToRGB_8u_P3AC4R = general_YUV444ToRGB_8u_P3AC4R;
|
||||
prims->RGBToYUV420_8u_P3AC4R = general_RGBToYUV420_8u_P3AC4R;
|
||||
|
||||
prims->RGBToYUV444_8u_P3AC4R = general_RGBToYUV444_8u_P3AC4R;
|
||||
prims->YUV420CombineToYUV444 = general_YUV420CombineToYUV444;
|
||||
prims->YUV444SplitToYUV420 = general_YUV444SplitToYUV420;
|
||||
|
||||
primitives_init_YUV_opt(prims);
|
||||
}
|
||||
|
||||
|
@ -22,27 +22,27 @@
|
||||
#include <emmintrin.h>
|
||||
#include <tmmintrin.h>
|
||||
|
||||
pstatus_t ssse3_YUV420ToRGB_8u_P3AC4R(const BYTE **pSrc, int *srcStep,
|
||||
BYTE *pDst, int dstStep, const prim_size_t *roi)
|
||||
pstatus_t ssse3_YUV420ToRGB_8u_P3AC4R(const BYTE **pSrc, const UINT32 *srcStep,
|
||||
BYTE *pDst, UINT32 dstStep, const prim_size_t *roi)
|
||||
{
|
||||
int lastRow, lastCol;
|
||||
UINT32 lastRow, lastCol;
|
||||
BYTE *UData,*VData,*YData;
|
||||
int i,nWidth,nHeight,VaddDst,VaddY,VaddU,VaddV;
|
||||
UINT32 i,nWidth,nHeight,VaddDst,VaddY,VaddU,VaddV;
|
||||
__m128i r0,r1,r2,r3,r4,r5,r6,r7;
|
||||
__m128i *buffer;
|
||||
|
||||
|
||||
/* last_line: if the last (U,V doubled) line should be skipped, set to 10B
|
||||
* last_column: if it's the last column in a line, set to 10B (for handling line-endings not multiple by four) */
|
||||
|
||||
buffer = _aligned_malloc(4 * 16, 16);
|
||||
|
||||
|
||||
YData = (BYTE*) pSrc[0];
|
||||
UData = (BYTE*) pSrc[1];
|
||||
VData = (BYTE*) pSrc[2];
|
||||
|
||||
|
||||
nWidth = roi->width;
|
||||
nHeight = roi->height;
|
||||
|
||||
|
||||
if ((lastCol = (nWidth & 3)))
|
||||
{
|
||||
switch (lastCol)
|
||||
@ -63,26 +63,26 @@ pstatus_t ssse3_YUV420ToRGB_8u_P3AC4R(const BYTE **pSrc, int *srcStep,
|
||||
_mm_store_si128(buffer+3,r7);
|
||||
lastCol = 1;
|
||||
}
|
||||
|
||||
|
||||
nWidth += 3;
|
||||
nWidth = nWidth >> 2;
|
||||
|
||||
|
||||
lastRow = nHeight & 1;
|
||||
nHeight++;
|
||||
nHeight = nHeight >> 1;
|
||||
|
||||
|
||||
VaddDst = (dstStep << 1) - (nWidth << 4);
|
||||
VaddY = (srcStep[0] << 1) - (nWidth << 2);
|
||||
VaddU = srcStep[1] - (((nWidth << 1) + 2) & 0xFFFC);
|
||||
VaddV = srcStep[2] - (((nWidth << 1) + 2) & 0xFFFC);
|
||||
|
||||
|
||||
while (nHeight-- > 0)
|
||||
{
|
||||
if (nHeight == 0)
|
||||
lastRow <<= 1;
|
||||
|
||||
i = 0;
|
||||
|
||||
|
||||
do
|
||||
{
|
||||
if (!(i & 0x01))
|
||||
@ -97,16 +97,16 @@ pstatus_t ssse3_YUV420ToRGB_8u_P3AC4R(const BYTE **pSrc, int *srcStep,
|
||||
r0 = _mm_cvtsi32_si128(*(UINT32 *)UData);
|
||||
r5 = _mm_set_epi32(0x80038003,0x80028002,0x80018001,0x80008000);
|
||||
r0 = _mm_shuffle_epi8(r0,r5);
|
||||
|
||||
|
||||
UData += 4;
|
||||
|
||||
|
||||
/* then we subtract 128 from each value, so we get D */
|
||||
r3 = _mm_set_epi16(128,128,128,128,128,128,128,128);
|
||||
r0 = _mm_subs_epi16(r0,r3);
|
||||
|
||||
|
||||
/* we need to do two things with our D, so let's store it for later use */
|
||||
r2 = r0;
|
||||
|
||||
|
||||
/* now we can multiply our D with 48 and unpack it to xmm4:xmm0
|
||||
* this is what we need to get G data later on */
|
||||
r4 = r0;
|
||||
@ -116,7 +116,7 @@ pstatus_t ssse3_YUV420ToRGB_8u_P3AC4R(const BYTE **pSrc, int *srcStep,
|
||||
r7 = r0;
|
||||
r0 = _mm_unpacklo_epi16(r0,r4);
|
||||
r4 = _mm_unpackhi_epi16(r7,r4);
|
||||
|
||||
|
||||
/* to get B data, we need to prepare a second value, D*475 */
|
||||
r1 = r2;
|
||||
r7 = _mm_set_epi16(475,475,475,475,475,475,475,475);
|
||||
@ -125,23 +125,23 @@ pstatus_t ssse3_YUV420ToRGB_8u_P3AC4R(const BYTE **pSrc, int *srcStep,
|
||||
r7 = r1;
|
||||
r1 = _mm_unpacklo_epi16(r1,r2);
|
||||
r7 = _mm_unpackhi_epi16(r7,r2);
|
||||
|
||||
|
||||
/* so we got something like this: xmm7:xmm1
|
||||
* this pair contains values for 16 pixel:
|
||||
* aabbccdd
|
||||
* aabbccdd, but we can only work on four pixel at once, so we need to save upper values */
|
||||
_mm_store_si128(buffer+1,r7);
|
||||
|
||||
|
||||
/* Now we've prepared U-data. Preparing V-data is actually the same, just with other coefficients */
|
||||
r2 = _mm_cvtsi32_si128(*(UINT32 *)VData);
|
||||
r2 = _mm_shuffle_epi8(r2,r5);
|
||||
|
||||
|
||||
VData += 4;
|
||||
|
||||
|
||||
r2 = _mm_subs_epi16(r2,r3);
|
||||
|
||||
|
||||
r5 = r2;
|
||||
|
||||
|
||||
/* this is also known as E*403, we need it to convert R data */
|
||||
r3 = r2;
|
||||
r7 = _mm_set_epi16(403,403,403,403,403,403,403,403);
|
||||
@ -150,10 +150,10 @@ pstatus_t ssse3_YUV420ToRGB_8u_P3AC4R(const BYTE **pSrc, int *srcStep,
|
||||
r7 = r2;
|
||||
r2 = _mm_unpacklo_epi16(r2,r3);
|
||||
r7 = _mm_unpackhi_epi16(r7,r3);
|
||||
|
||||
|
||||
/* and preserve upper four values for future ... */
|
||||
_mm_store_si128(buffer+2,r7);
|
||||
|
||||
|
||||
/* doing this step: E*120 */
|
||||
r3 = r5;
|
||||
r7 = _mm_set_epi16(120,120,120,120,120,120,120,120);
|
||||
@ -162,12 +162,12 @@ pstatus_t ssse3_YUV420ToRGB_8u_P3AC4R(const BYTE **pSrc, int *srcStep,
|
||||
r7 = r3;
|
||||
r3 = _mm_unpacklo_epi16(r3,r5);
|
||||
r7 = _mm_unpackhi_epi16(r7,r5);
|
||||
|
||||
|
||||
/* now we complete what we've begun above:
|
||||
* (48*D) + (120*E) = (48*D +120*E) */
|
||||
r0 = _mm_add_epi32(r0,r3);
|
||||
r4 = _mm_add_epi32(r4,r7);
|
||||
|
||||
|
||||
/* and store to memory ! */
|
||||
_mm_store_si128(buffer,r4);
|
||||
}
|
||||
@ -180,25 +180,25 @@ pstatus_t ssse3_YUV420ToRGB_8u_P3AC4R(const BYTE **pSrc, int *srcStep,
|
||||
r2 = _mm_load_si128(buffer+2);
|
||||
r0 = _mm_load_si128(buffer);
|
||||
}
|
||||
|
||||
|
||||
if (++i == nWidth)
|
||||
lastCol <<= 1;
|
||||
|
||||
|
||||
/* We didn't produce any output yet, so let's do so!
|
||||
* Ok, fetch four pixel from the Y-data array and shuffle them like this:
|
||||
* 00d0 00c0 00b0 00a0, to get signed dwords and multiply by 256 */
|
||||
r4 = _mm_cvtsi32_si128(*(UINT32 *)YData);
|
||||
r7 = _mm_set_epi32(0x80800380,0x80800280,0x80800180,0x80800080);
|
||||
r4 = _mm_shuffle_epi8(r4,r7);
|
||||
|
||||
|
||||
r5 = r4;
|
||||
r6 = r4;
|
||||
|
||||
|
||||
/* no we can perform the "real" conversion itself and produce output! */
|
||||
r4 = _mm_add_epi32(r4,r2);
|
||||
r5 = _mm_sub_epi32(r5,r0);
|
||||
r6 = _mm_add_epi32(r6,r1);
|
||||
|
||||
|
||||
/* in the end, we only need bytes for RGB values.
|
||||
* So, what do we do? right! shifting left makes values bigger and thats always good.
|
||||
* before we had dwords of data, and by shifting left and treating the result
|
||||
@ -208,7 +208,7 @@ pstatus_t ssse3_YUV420ToRGB_8u_P3AC4R(const BYTE **pSrc, int *srcStep,
|
||||
r4 = _mm_slli_epi32(r4,8);
|
||||
r5 = _mm_slli_epi32(r5,8);
|
||||
r6 = _mm_slli_epi32(r6,8);
|
||||
|
||||
|
||||
/* one thing we still have to face is the clip() function ...
|
||||
* we have still signed words, and there are those min/max instructions in SSE2 ...
|
||||
* the max instruction takes always the bigger of the two operands and stores it in the first one,
|
||||
@ -219,35 +219,35 @@ pstatus_t ssse3_YUV420ToRGB_8u_P3AC4R(const BYTE **pSrc, int *srcStep,
|
||||
r4 = _mm_max_epi16(r4,r7);
|
||||
r5 = _mm_max_epi16(r5,r7);
|
||||
r6 = _mm_max_epi16(r6,r7);
|
||||
|
||||
|
||||
/* the same thing just completely different can be used to limit our values to 255,
|
||||
* but now using the min instruction and 255s */
|
||||
r7 = _mm_set_epi32(0x00FF0000,0x00FF0000,0x00FF0000,0x00FF0000);
|
||||
r4 = _mm_min_epi16(r4,r7);
|
||||
r5 = _mm_min_epi16(r5,r7);
|
||||
r6 = _mm_min_epi16(r6,r7);
|
||||
|
||||
|
||||
/* Now we got our bytes.
|
||||
* the moment has come to assemble the three channels R,G and B to the xrgb dwords
|
||||
* on Red channel we just have to and each futural dword with 00FF0000H */
|
||||
//r7=_mm_set_epi32(0x00FF0000,0x00FF0000,0x00FF0000,0x00FF0000);
|
||||
r4 = _mm_and_si128(r4,r7);
|
||||
|
||||
|
||||
/* on Green channel we have to shuffle somehow, so we get something like this:
|
||||
* 00d0 00c0 00b0 00a0 */
|
||||
r7 = _mm_set_epi32(0x80800E80,0x80800A80,0x80800680,0x80800280);
|
||||
r5 = _mm_shuffle_epi8(r5,r7);
|
||||
|
||||
|
||||
/* and on Blue channel that one:
|
||||
* 000d 000c 000b 000a */
|
||||
r7 = _mm_set_epi32(0x8080800E,0x8080800A,0x80808006,0x80808002);
|
||||
r6 = _mm_shuffle_epi8(r6,r7);
|
||||
|
||||
|
||||
/* and at last we or it together and get this one:
|
||||
* xrgb xrgb xrgb xrgb */
|
||||
r4 = _mm_or_si128(r4,r5);
|
||||
r4 = _mm_or_si128(r4,r6);
|
||||
|
||||
|
||||
/* Only thing to do know is writing data to memory, but this gets a bit more
|
||||
* complicated if the width is not a multiple of four and it is the last column in line. */
|
||||
if (lastCol & 0x02)
|
||||
@ -269,7 +269,7 @@ pstatus_t ssse3_YUV420ToRGB_8u_P3AC4R(const BYTE **pSrc, int *srcStep,
|
||||
r4 = _mm_or_si128(r4,r6);
|
||||
}
|
||||
_mm_storeu_si128((__m128i *)pDst,r4);
|
||||
|
||||
|
||||
if (!(lastRow & 0x02))
|
||||
{
|
||||
/* Because UV data is the same for two lines, we can process the secound line just here,
|
||||
@ -280,40 +280,40 @@ pstatus_t ssse3_YUV420ToRGB_8u_P3AC4R(const BYTE **pSrc, int *srcStep,
|
||||
r4 = _mm_cvtsi32_si128(*(UINT32 *)(YData+srcStep[0]));
|
||||
r7 = _mm_set_epi32(0x80800380,0x80800280,0x80800180,0x80800080);
|
||||
r4 = _mm_shuffle_epi8(r4,r7);
|
||||
|
||||
|
||||
r5 = r4;
|
||||
r6 = r4;
|
||||
|
||||
|
||||
r4 = _mm_add_epi32(r4,r2);
|
||||
r5 = _mm_sub_epi32(r5,r0);
|
||||
r6 = _mm_add_epi32(r6,r1);
|
||||
|
||||
|
||||
r4 = _mm_slli_epi32(r4,8);
|
||||
r5 = _mm_slli_epi32(r5,8);
|
||||
r6 = _mm_slli_epi32(r6,8);
|
||||
|
||||
|
||||
r7 = _mm_set_epi32(0,0,0,0);
|
||||
r4 = _mm_max_epi16(r4,r7);
|
||||
r5 = _mm_max_epi16(r5,r7);
|
||||
r6 = _mm_max_epi16(r6,r7);
|
||||
|
||||
|
||||
r7 = _mm_set_epi32(0x00FF0000,0x00FF0000,0x00FF0000,0x00FF0000);
|
||||
r4 = _mm_min_epi16(r4,r7);
|
||||
r5 = _mm_min_epi16(r5,r7);
|
||||
r6 = _mm_min_epi16(r6,r7);
|
||||
|
||||
|
||||
r7 = _mm_set_epi32(0x00FF0000,0x00FF0000,0x00FF0000,0x00FF0000);
|
||||
r4 = _mm_and_si128(r4,r7);
|
||||
|
||||
|
||||
r7 = _mm_set_epi32(0x80800E80,0x80800A80,0x80800680,0x80800280);
|
||||
r5 = _mm_shuffle_epi8(r5,r7);
|
||||
|
||||
|
||||
r7 = _mm_set_epi32(0x8080800E,0x8080800A,0x80808006,0x80808002);
|
||||
r6 = _mm_shuffle_epi8(r6,r7);
|
||||
|
||||
|
||||
r4 = _mm_or_si128(r4,r5);
|
||||
r4 = _mm_or_si128(r4,r6);
|
||||
|
||||
|
||||
if (lastCol & 0x02)
|
||||
{
|
||||
r6 = _mm_load_si128(buffer+3);
|
||||
@ -321,20 +321,20 @@ pstatus_t ssse3_YUV420ToRGB_8u_P3AC4R(const BYTE **pSrc, int *srcStep,
|
||||
r5 = _mm_lddqu_si128((__m128i *)(pDst+dstStep));
|
||||
r6 = _mm_andnot_si128(r6,r5);
|
||||
r4 = _mm_or_si128(r4,r6);
|
||||
|
||||
|
||||
/* only thing is, we should shift [rbp-42] back here, because we have processed the last column,
|
||||
* and this "special condition" can be released */
|
||||
lastCol >>= 1;
|
||||
}
|
||||
_mm_storeu_si128((__m128i *)(pDst+dstStep),r4);
|
||||
}
|
||||
|
||||
|
||||
/* after all we have to increase the destination- and Y-data pointer by four pixel */
|
||||
pDst += 16;
|
||||
YData += 4;
|
||||
}
|
||||
while (i < nWidth);
|
||||
|
||||
|
||||
/* after each line we have to add the scanline to the destination pointer, because
|
||||
* we are processing two lines at once, but only increasing the destination pointer
|
||||
* in the first line. Well, we only have one pointer, so it's the easiest way to access
|
||||
@ -343,10 +343,10 @@ pstatus_t ssse3_YUV420ToRGB_8u_P3AC4R(const BYTE **pSrc, int *srcStep,
|
||||
* output buffer was "designed" for 1920p HD, we have to add the remaining length for each line,
|
||||
* to get into the next line. */
|
||||
pDst += VaddDst;
|
||||
|
||||
|
||||
/* same thing has to be done for Y-data, but with iStride[0] instead of the target scanline */
|
||||
YData += VaddY;
|
||||
|
||||
|
||||
/* and again for UV data, but here it's enough to add the remaining length, because
|
||||
* UV data is the same for two lines and there exists only one "UV line" on two "real lines" */
|
||||
UData += VaddU;
|
||||
@ -354,7 +354,7 @@ pstatus_t ssse3_YUV420ToRGB_8u_P3AC4R(const BYTE **pSrc, int *srcStep,
|
||||
}
|
||||
|
||||
_aligned_free(buffer);
|
||||
|
||||
|
||||
return PRIMITIVES_SUCCESS;
|
||||
}
|
||||
#endif
|
||||
|
@ -14,6 +14,7 @@ set(${MODULE_PREFIX}_TESTS
|
||||
TestPrimitivesSet.c
|
||||
TestPrimitivesShift.c
|
||||
TestPrimitivesSign.c
|
||||
TestPrimitivesYUV.c
|
||||
TestPrimitivesYCbCr.c
|
||||
TestPrimitivesYCoCg.c)
|
||||
|
||||
|
@ -57,8 +57,10 @@ static BOOL try_16To32(
|
||||
const UINT16 *src;
|
||||
UINT32 ALIGN(outNN1[4096+3]), ALIGN(outAN1[4096+3]),
|
||||
ALIGN(outNI1[4096+3]), ALIGN(outAI1[4096+3]);
|
||||
#ifdef WITH_SSE2
|
||||
UINT32 ALIGN(outNN2[4096+3]), ALIGN(outAN2[4096+3]),
|
||||
ALIGN(outNI2[4096+3]), ALIGN(outAI2[4096+3]);
|
||||
#endif
|
||||
|
||||
assert(sOffset < 4);
|
||||
assert(dOffset < 4);
|
||||
@ -161,7 +163,7 @@ int test_RGB565ToARGB_16u32u_C3C4_func(void)
|
||||
STD_SPEED_TEST(
|
||||
test16to32_speed, UINT16, UINT32, PRIM_NOP,
|
||||
TRUE, general_RGB565ToARGB_16u32u_C3C4(
|
||||
(const UINT16 *) src1, 64*2, (UINT32 *) dst, 64*4,
|
||||
(const UINT16 *) src1, 64*2, (UINT32 *) dst, 64*4,
|
||||
64,64, TRUE, TRUE),
|
||||
#ifdef WITH_SSE2
|
||||
TRUE, sse3_RGB565ToARGB_16u32u_C3C4(
|
||||
@ -182,7 +184,7 @@ int test_RGB565ToARGB_16u32u_C3C4_speed(void)
|
||||
|
||||
get_random_data(src, sizeof(src));
|
||||
|
||||
test16to32_speed("16-to-32bpp", "aligned",
|
||||
test16to32_speed("16-to-32bpp", "aligned",
|
||||
(const UINT16 *) src, 0, 0, (UINT32 *) dst,
|
||||
size_array, 1, RGB_TRIAL_ITERATIONS, TEST_TIME);
|
||||
return SUCCESS;
|
||||
|
@ -38,12 +38,14 @@ extern pstatus_t ssse3_YCoCgRToRGB_8u_AC4R(const BYTE *pSrc, INT32 srcStep,
|
||||
/* ------------------------------------------------------------------------- */
|
||||
int test_YCoCgRToRGB_8u_AC4R_func(void)
|
||||
{
|
||||
#ifdef WITH_SSE2
|
||||
int i;
|
||||
INT32 ALIGN(out_sse[4098]), ALIGN(out_sse_inv[4098]);
|
||||
#endif
|
||||
INT32 ALIGN(in[4098]);
|
||||
INT32 ALIGN(out_c[4098]), ALIGN(out_c_inv[4098]);
|
||||
INT32 ALIGN(out_sse[4098]), ALIGN(out_sse_inv[4098]);
|
||||
char testStr[256];
|
||||
BOOL failed = FALSE;
|
||||
int i;
|
||||
|
||||
testStr[0] = '\0';
|
||||
get_random_data(in, sizeof(in));
|
||||
|
427
libfreerdp/primitives/test/TestPrimitivesYUV.c
Normal file
427
libfreerdp/primitives/test/TestPrimitivesYUV.c
Normal file
@ -0,0 +1,427 @@
|
||||
|
||||
#include "prim_test.h"
|
||||
|
||||
#include <winpr/wlog.h>
|
||||
#include <winpr/crypto.h>
|
||||
#include <freerdp/primitives.h>
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#define TAG __FILE__
|
||||
|
||||
/* YUV to RGB conversion is lossy, so consider every value only
|
||||
* differing by less than 2 abs equal. */
|
||||
static BOOL similar(const BYTE* src, const BYTE* dst, size_t size)
|
||||
{
|
||||
size_t x;
|
||||
|
||||
for (x=0; x<size; x++)
|
||||
{
|
||||
volatile double val1 = (double)src[x];
|
||||
volatile double val2 = (double)dst[x];
|
||||
volatile double diff = val1 - val2;
|
||||
|
||||
if (abs(diff) > 2)
|
||||
{
|
||||
fprintf(stderr, "%zd %02X : %02X diff=%lf\n", x, val1, val2, diff);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void get_size(UINT32* width, UINT32* height)
|
||||
{
|
||||
winpr_RAND((BYTE*)width, sizeof(*width));
|
||||
winpr_RAND((BYTE*)height, sizeof(*height));
|
||||
|
||||
// TODO: Algorithm only works on even resolutions...
|
||||
*width = (*width % 4000) << 1;
|
||||
*height = (*height % 4000 << 1);
|
||||
}
|
||||
|
||||
static BOOL check_padding(const BYTE* psrc, size_t size, size_t padding, const char* buffer)
|
||||
{
|
||||
size_t x;
|
||||
BOOL rc = TRUE;
|
||||
const BYTE* src;
|
||||
const BYTE* esrc;
|
||||
size_t halfPad = (padding+1)/2;
|
||||
|
||||
if (!psrc)
|
||||
return FALSE;
|
||||
|
||||
src = psrc - halfPad;
|
||||
esrc = src + size + halfPad;
|
||||
for (x=0; x<halfPad; x++)
|
||||
{
|
||||
const BYTE s = *src++;
|
||||
const BYTE d = *esrc++;
|
||||
if (s != 'A')
|
||||
{
|
||||
size_t start = x;
|
||||
while((x < halfPad) && (*esrc++ != 'A'))
|
||||
x++;
|
||||
|
||||
fprintf(stderr, "Buffer underflow detected %02x != %02X %s [%zd-%zd]\n",
|
||||
d, 'A', buffer, start, x);
|
||||
return FALSE;
|
||||
}
|
||||
if(d != 'A')
|
||||
{
|
||||
size_t start = x;
|
||||
while((x < halfPad) && (*esrc++ != 'A'))
|
||||
x++;
|
||||
|
||||
fprintf(stderr, "Buffer overflow detected %02x != %02X %s [%zd-%zd]\n",
|
||||
d, 'A', buffer, start, x);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void* set_padding(size_t size, size_t padding)
|
||||
{
|
||||
size_t halfPad = (padding + 1) / 2;
|
||||
BYTE* psrc;
|
||||
BYTE* src = calloc(1, size + 2 * halfPad);
|
||||
if (!src)
|
||||
return NULL;
|
||||
|
||||
memset(&src[0], 'A', halfPad);
|
||||
memset(&src[halfPad+size], 'A', halfPad);
|
||||
|
||||
psrc = &src[halfPad];
|
||||
if (!check_padding(psrc, size, padding, "init"))
|
||||
{
|
||||
free (src);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return psrc;
|
||||
}
|
||||
|
||||
static void free_padding(void* src, size_t padding)
|
||||
{
|
||||
BYTE* ptr;
|
||||
if (!src)
|
||||
return;
|
||||
|
||||
ptr = ((BYTE*)src) - (padding+1)/2;
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
/* Create 2 pseudo YUV420 frames of same size.
|
||||
* Combine them and check, if the data is at the expected position. */
|
||||
static BOOL TestPrimitiveYUVCombine(void)
|
||||
{
|
||||
UINT32 x, y, i;
|
||||
UINT32 awidth, aheight;
|
||||
BOOL rc = FALSE;
|
||||
BYTE* luma[3] = { 0 };
|
||||
BYTE* chroma[3] = { 0 };
|
||||
BYTE* yuv[3] = { 0 };
|
||||
BYTE* pmain[3] = { 0 };
|
||||
BYTE* paux[3] = { 0 };
|
||||
UINT32 lumaStride[3];
|
||||
UINT32 chromaStride[3];
|
||||
UINT32 yuvStride[3];
|
||||
size_t padding = 10000;
|
||||
prim_size_t roi;
|
||||
primitives_t* prims = primitives_get();
|
||||
|
||||
get_size(&roi.width, &roi.height);
|
||||
awidth = roi.width + 16 - roi.width % 16;
|
||||
aheight = roi.height + 16 - roi.height % 16;
|
||||
|
||||
fprintf(stderr, "Running YUVCombine on frame size %lux%lu [%lux%lu]\n",
|
||||
roi.width, roi.height, awidth, aheight);
|
||||
if (!prims || !prims->YUV420CombineToYUV444)
|
||||
goto fail;
|
||||
|
||||
for (x=0; x<3; x++)
|
||||
{
|
||||
size_t halfStride = ((x>0)?awidth/2:awidth);
|
||||
size_t size = aheight * awidth;
|
||||
size_t halfSize = ((x>0)?halfStride*aheight/2:awidth*aheight);
|
||||
|
||||
yuvStride[x] = awidth;
|
||||
if (!(yuv[x] = set_padding(size, padding)))
|
||||
goto fail;
|
||||
|
||||
lumaStride[x] = halfStride;
|
||||
if (!(luma[x] = set_padding(halfSize, padding)))
|
||||
goto fail;
|
||||
|
||||
if (!(pmain[x] = set_padding(halfSize, padding)))
|
||||
goto fail;
|
||||
|
||||
chromaStride[x] = halfStride;
|
||||
if (!(chroma[x] = set_padding(halfSize, padding)))
|
||||
goto fail;
|
||||
|
||||
if (!(paux[x] = set_padding(halfSize, padding)))
|
||||
goto fail;
|
||||
|
||||
memset(luma[x], 0xAB + 3*x, halfSize);
|
||||
memset(chroma[x], 0x80 + 2*x, halfSize);
|
||||
|
||||
if (!check_padding(luma[x], halfSize, padding, "luma"))
|
||||
goto fail;
|
||||
if (!check_padding(chroma[x], halfSize, padding, "chroma"))
|
||||
goto fail;
|
||||
if (!check_padding(pmain[x], halfSize, padding, "main"))
|
||||
goto fail;
|
||||
if (!check_padding(paux[x], halfSize, padding, "aux"))
|
||||
goto fail;
|
||||
if (!check_padding(yuv[x], size, padding, "yuv"))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (prims->YUV420CombineToYUV444((const BYTE**)luma, lumaStride,
|
||||
(const BYTE**) chroma, chromaStride,
|
||||
yuv, yuvStride, &roi) != PRIMITIVES_SUCCESS)
|
||||
goto fail;
|
||||
|
||||
for (x=0; x<3; x++)
|
||||
{
|
||||
size_t halfStride = ((x>0)?awidth/2:awidth);
|
||||
size_t size = aheight * awidth;
|
||||
size_t halfSize = ((x>0)?halfStride*aheight/2:awidth*aheight);
|
||||
|
||||
if (!check_padding(luma[x], halfSize, padding, "luma"))
|
||||
goto fail;
|
||||
if (!check_padding(chroma[x], halfSize, padding, "chroma"))
|
||||
goto fail;
|
||||
if (!check_padding(yuv[x], size, padding, "yuv"))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (prims->YUV444SplitToYUV420(yuv, yuvStride, pmain, lumaStride,
|
||||
paux, chromaStride, &roi) != PRIMITIVES_SUCCESS)
|
||||
goto fail;
|
||||
|
||||
for (x=0; x<3; x++)
|
||||
{
|
||||
size_t halfStride = ((x>0)?awidth/2:awidth);
|
||||
size_t size = aheight * awidth;
|
||||
size_t halfSize = ((x>0)?halfStride*aheight/2:awidth*aheight);
|
||||
|
||||
if (!check_padding(pmain[x], halfSize, padding, "main"))
|
||||
goto fail;
|
||||
if (!check_padding(paux[x], halfSize, padding, "aux"))
|
||||
goto fail;
|
||||
if (!check_padding(yuv[x], size, padding, "yuv"))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
for (i=0; i<3; i++)
|
||||
{
|
||||
for (y=0; y<roi.height; y++)
|
||||
{
|
||||
UINT32 w = roi.width;
|
||||
UINT32 lstride = lumaStride[i];
|
||||
UINT32 cstride = chromaStride[i];
|
||||
|
||||
if (i > 0)
|
||||
{
|
||||
w = (roi.width+3) / 4;
|
||||
if (roi.height > (roi.height+1)/2)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!similar(luma[i] + y * lstride,
|
||||
pmain[i] + y * lstride,
|
||||
w))
|
||||
goto fail;
|
||||
|
||||
/* Need to ignore lines of destination Y plane,
|
||||
* if the lines are not a multiple of 16
|
||||
* as the UV planes are packed in 8 line stripes. */
|
||||
if (i == 0)
|
||||
{
|
||||
/* TODO: This check is not perfect, it does not
|
||||
* include the last V lines packed to the Y
|
||||
* frame. */
|
||||
UINT32 rem = roi.height % 16;
|
||||
if (y > roi.height - rem)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!similar(chroma[i] + y * cstride,
|
||||
paux[i] + y * cstride,
|
||||
w))
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
rc = TRUE;
|
||||
fail:
|
||||
for (x=0; x<3; x++)
|
||||
{
|
||||
free_padding(yuv[x], padding);
|
||||
free_padding(luma[x], padding);
|
||||
free_padding(chroma[x], padding);
|
||||
free_padding(pmain[x], padding);
|
||||
free_padding(paux[x], padding);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static BOOL TestPrimitiveYUV(BOOL use444)
|
||||
{
|
||||
BOOL rc = FALSE;
|
||||
UINT32 x, y;
|
||||
UINT32 awidth, aheight;
|
||||
BYTE* yuv[3] = {0};
|
||||
UINT32 yuv_step[3];
|
||||
prim_size_t roi;
|
||||
BYTE* rgb = NULL;
|
||||
BYTE* rgb_dst = NULL;
|
||||
size_t size;
|
||||
primitives_t* prims = primitives_get();
|
||||
size_t uvsize, uvwidth;
|
||||
size_t padding = 10000;
|
||||
size_t stride;
|
||||
|
||||
get_size(&roi.width, &roi.height);
|
||||
|
||||
/* Buffers need to be 16x16 aligned. */
|
||||
awidth = roi.width + 16 - roi.width % 16;
|
||||
aheight = roi.height + 16 - roi.height % 16;
|
||||
|
||||
stride = awidth * sizeof(UINT32);
|
||||
size = awidth * aheight;
|
||||
if (use444)
|
||||
{
|
||||
uvwidth = awidth;
|
||||
uvsize = size;
|
||||
if (!prims || !prims->RGBToYUV444_8u_P3AC4R || !prims->YUV444ToRGB_8u_P3AC4R)
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
uvwidth = (awidth + 1) / 2;
|
||||
uvsize = (aheight + 1) / 2 * uvwidth;
|
||||
if (!prims || !prims->RGBToYUV420_8u_P3AC4R || !prims->YUV420ToRGB_8u_P3AC4R)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
fprintf(stderr, "Running AVC%s on frame size %lux%lu\n", use444 ? "444" : "420",
|
||||
roi.width, roi.height);
|
||||
|
||||
/* Test RGB to YUV444 conversion and vice versa */
|
||||
if (!(rgb = set_padding(size * sizeof(UINT32), padding)))
|
||||
goto fail;
|
||||
|
||||
if (!(rgb_dst = set_padding(size * sizeof(UINT32), padding)))
|
||||
goto fail;
|
||||
|
||||
if (!(yuv[0] = set_padding(size, padding)))
|
||||
goto fail;
|
||||
|
||||
if (!(yuv[1] = set_padding(uvsize, padding)))
|
||||
goto fail;
|
||||
|
||||
if (!(yuv[2] = set_padding(uvsize, padding)))
|
||||
goto fail;
|
||||
|
||||
for (y=0; y<roi.height; y++)
|
||||
{
|
||||
BYTE* line = &rgb[y*stride];
|
||||
for (x=0; x<roi.width; x++)
|
||||
{
|
||||
line[x*4+0] = 0x81;
|
||||
line[x*4+1] = 0x33;
|
||||
line[x*4+2] = 0xAB;
|
||||
line[x*4+3] = 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
yuv_step[0] = awidth;
|
||||
yuv_step[1] = uvwidth;
|
||||
yuv_step[2] = uvwidth;
|
||||
|
||||
if (use444)
|
||||
{
|
||||
if (prims->RGBToYUV444_8u_P3AC4R(rgb, stride, yuv, yuv_step, &roi) != PRIMITIVES_SUCCESS)
|
||||
goto fail;
|
||||
}
|
||||
else if (prims->RGBToYUV420_8u_P3AC4R(rgb, stride, yuv, yuv_step, &roi) != PRIMITIVES_SUCCESS)
|
||||
goto fail;
|
||||
|
||||
if (!check_padding(rgb, size * sizeof(UINT32), padding, "rgb"))
|
||||
goto fail;
|
||||
|
||||
if ((!check_padding(yuv[0], size, padding, "Y")) ||
|
||||
(!check_padding(yuv[1], uvsize, padding, "U")) ||
|
||||
(!check_padding(yuv[2], uvsize, padding, "V")))
|
||||
goto fail;
|
||||
|
||||
if (use444)
|
||||
{
|
||||
if (prims->YUV444ToRGB_8u_P3AC4R((const BYTE**)yuv, yuv_step, rgb_dst, stride, &roi) != PRIMITIVES_SUCCESS)
|
||||
goto fail;
|
||||
}
|
||||
else if (prims->YUV420ToRGB_8u_P3AC4R((const BYTE**)yuv, yuv_step, rgb_dst, stride, &roi) != PRIMITIVES_SUCCESS)
|
||||
goto fail;
|
||||
|
||||
if (!check_padding(rgb_dst, size * sizeof(UINT32), padding, "rgb dst"))
|
||||
goto fail;
|
||||
|
||||
if ((!check_padding(yuv[0], size, padding, "Y")) ||
|
||||
(!check_padding(yuv[1], uvsize, padding, "U")) ||
|
||||
(!check_padding(yuv[2], uvsize, padding, "V")))
|
||||
goto fail;
|
||||
|
||||
for (y=0; y<roi.height; y++)
|
||||
{
|
||||
BYTE* srgb = &rgb[y*stride];
|
||||
BYTE* drgb = &rgb_dst[y*stride];
|
||||
|
||||
if (!similar(srgb, drgb, roi.width*sizeof(UINT32)))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
rc = TRUE;
|
||||
fail:
|
||||
free_padding (rgb, padding);
|
||||
free_padding (rgb_dst, padding);
|
||||
free_padding (yuv[0], padding);
|
||||
free_padding (yuv[1], padding);
|
||||
free_padding (yuv[2], padding);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int TestPrimitivesYUV(int argc, char* argv[])
|
||||
{
|
||||
UINT32 x;
|
||||
int rc = -1;
|
||||
|
||||
primitives_init();
|
||||
|
||||
for (x=0; x<10; x++)
|
||||
{
|
||||
/* TODO: This test fails on value comparison,
|
||||
* there seems to be some issue left with encoder / decoder pass.
|
||||
if (!TestPrimitiveYUV(FALSE))
|
||||
goto end;
|
||||
*/
|
||||
if (!TestPrimitiveYUV(TRUE))
|
||||
goto end;
|
||||
if (!TestPrimitiveYUVCombine())
|
||||
goto end;
|
||||
}
|
||||
rc = 0;
|
||||
end:
|
||||
primitives_deinit();
|
||||
return rc;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user