2014-07-28 17:42:23 -04:00
|
|
|
/**
|
|
|
|
|
* FreeRDP: A Remote Desktop Protocol Implementation
|
|
|
|
|
* Progressive Codec Bitmap Compression
|
|
|
|
|
*
|
|
|
|
|
* Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
2019-12-10 16:19:20 +01:00
|
|
|
* Copyright 2019 Armin Novak <armin.novak@thincast.com>
|
|
|
|
|
* Copyright 2019 Thincast Technologies GmbH
|
2014-07-28 17:42:23 -04:00
|
|
|
*
|
|
|
|
|
* 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.
|
|
|
|
|
*/
|
|
|
|
|
|
2022-02-16 11:20:38 +01:00
|
|
|
#include <freerdp/config.h>
|
2014-07-28 17:42:23 -04:00
|
|
|
|
2022-01-28 09:07:27 +01:00
|
|
|
#include <winpr/assert.h>
|
2024-12-19 14:45:06 +01:00
|
|
|
#include <winpr/cast.h>
|
2014-07-28 17:42:23 -04:00
|
|
|
#include <winpr/crt.h>
|
|
|
|
|
#include <winpr/print.h>
|
|
|
|
|
#include <winpr/bitstream.h>
|
|
|
|
|
|
2014-08-18 19:12:08 -04:00
|
|
|
#include <freerdp/primitives.h>
|
2014-07-28 17:42:23 -04:00
|
|
|
#include <freerdp/codec/color.h>
|
|
|
|
|
#include <freerdp/codec/progressive.h>
|
2016-04-05 17:07:45 +02:00
|
|
|
#include <freerdp/codec/region.h>
|
2014-09-12 14:36:29 +02:00
|
|
|
#include <freerdp/log.h>
|
2014-07-28 17:42:23 -04:00
|
|
|
|
2014-08-18 19:12:08 -04:00
|
|
|
#include "rfx_differential.h"
|
|
|
|
|
#include "rfx_quantization.h"
|
2019-12-16 08:34:42 +01:00
|
|
|
#include "rfx_dwt.h"
|
2016-11-23 13:21:59 +01:00
|
|
|
#include "rfx_rlgr.h"
|
2023-10-06 13:22:17 +02:00
|
|
|
#include "rfx_constants.h"
|
2021-05-24 11:28:02 +02:00
|
|
|
#include "rfx_types.h"
|
2017-01-18 16:41:02 +01:00
|
|
|
#include "progressive.h"
|
2014-08-18 19:12:08 -04:00
|
|
|
|
2014-09-12 14:36:29 +02:00
|
|
|
#define TAG FREERDP_TAG("codec.progressive")
|
|
|
|
|
|
2022-02-14 13:59:22 +00:00
|
|
|
typedef struct
|
2017-02-20 18:31:58 +01:00
|
|
|
{
|
|
|
|
|
BOOL nonLL;
|
|
|
|
|
wBitStream* srl;
|
|
|
|
|
wBitStream* raw;
|
|
|
|
|
|
|
|
|
|
/* SRL state */
|
|
|
|
|
|
2019-12-10 16:19:20 +01:00
|
|
|
UINT32 kp;
|
2017-02-20 18:31:58 +01:00
|
|
|
int nz;
|
|
|
|
|
BOOL mode;
|
2022-02-14 13:59:22 +00:00
|
|
|
} RFX_PROGRESSIVE_UPGRADE_STATE;
|
2017-02-20 18:31:58 +01:00
|
|
|
|
2025-09-22 12:19:02 +02:00
|
|
|
static inline void
|
2024-05-29 23:53:33 +02:00
|
|
|
progressive_component_codec_quant_read(wStream* WINPR_RESTRICT s,
|
|
|
|
|
RFX_COMPONENT_CODEC_QUANT* WINPR_RESTRICT quantVal)
|
2014-09-02 13:31:40 -04:00
|
|
|
{
|
2024-01-23 16:49:54 +01:00
|
|
|
BYTE b = 0;
|
2019-12-10 16:19:20 +01:00
|
|
|
Stream_Read_UINT8(s, b);
|
|
|
|
|
quantVal->LL3 = b & 0x0F;
|
|
|
|
|
quantVal->HL3 = b >> 4;
|
|
|
|
|
Stream_Read_UINT8(s, b);
|
|
|
|
|
quantVal->LH3 = b & 0x0F;
|
|
|
|
|
quantVal->HH3 = b >> 4;
|
|
|
|
|
Stream_Read_UINT8(s, b);
|
|
|
|
|
quantVal->HL2 = b & 0x0F;
|
|
|
|
|
quantVal->LH2 = b >> 4;
|
|
|
|
|
Stream_Read_UINT8(s, b);
|
|
|
|
|
quantVal->HH2 = b & 0x0F;
|
|
|
|
|
quantVal->HL1 = b >> 4;
|
|
|
|
|
Stream_Read_UINT8(s, b);
|
|
|
|
|
quantVal->LH1 = b & 0x0F;
|
|
|
|
|
quantVal->HH1 = b >> 4;
|
2014-09-02 13:31:40 -04:00
|
|
|
}
|
|
|
|
|
|
2025-09-22 12:19:02 +02:00
|
|
|
static inline void progressive_rfx_quant_add(const RFX_COMPONENT_CODEC_QUANT* WINPR_RESTRICT q1,
|
2024-05-29 23:53:33 +02:00
|
|
|
const RFX_COMPONENT_CODEC_QUANT* WINPR_RESTRICT q2,
|
2019-11-06 15:24:51 +01:00
|
|
|
RFX_COMPONENT_CODEC_QUANT* dst)
|
2014-08-28 12:14:28 -04:00
|
|
|
{
|
|
|
|
|
dst->HL1 = q1->HL1 + q2->HL1; /* HL1 */
|
|
|
|
|
dst->LH1 = q1->LH1 + q2->LH1; /* LH1 */
|
|
|
|
|
dst->HH1 = q1->HH1 + q2->HH1; /* HH1 */
|
|
|
|
|
dst->HL2 = q1->HL2 + q2->HL2; /* HL2 */
|
|
|
|
|
dst->LH2 = q1->LH2 + q2->LH2; /* LH2 */
|
|
|
|
|
dst->HH2 = q1->HH2 + q2->HH2; /* HH2 */
|
|
|
|
|
dst->HL3 = q1->HL3 + q2->HL3; /* HL3 */
|
|
|
|
|
dst->LH3 = q1->LH3 + q2->LH3; /* LH3 */
|
|
|
|
|
dst->HH3 = q1->HH3 + q2->HH3; /* HH3 */
|
|
|
|
|
dst->LL3 = q1->LL3 + q2->LL3; /* LL3 */
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-22 12:19:02 +02:00
|
|
|
static inline void progressive_rfx_quant_lsub(RFX_COMPONENT_CODEC_QUANT* WINPR_RESTRICT q, int val)
|
2014-08-28 12:14:28 -04:00
|
|
|
{
|
|
|
|
|
q->HL1 -= val; /* HL1 */
|
|
|
|
|
q->LH1 -= val; /* LH1 */
|
|
|
|
|
q->HH1 -= val; /* HH1 */
|
|
|
|
|
q->HL2 -= val; /* HL2 */
|
|
|
|
|
q->LH2 -= val; /* LH2 */
|
|
|
|
|
q->HH2 -= val; /* HH2 */
|
|
|
|
|
q->HL3 -= val; /* HL3 */
|
|
|
|
|
q->LH3 -= val; /* LH3 */
|
|
|
|
|
q->HH3 -= val; /* HH3 */
|
|
|
|
|
q->LL3 -= val; /* LL3 */
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-22 12:19:02 +02:00
|
|
|
static inline void progressive_rfx_quant_sub(const RFX_COMPONENT_CODEC_QUANT* WINPR_RESTRICT q1,
|
2024-05-29 23:53:33 +02:00
|
|
|
const RFX_COMPONENT_CODEC_QUANT* WINPR_RESTRICT q2,
|
2019-11-06 15:24:51 +01:00
|
|
|
RFX_COMPONENT_CODEC_QUANT* dst)
|
2014-08-28 12:14:28 -04:00
|
|
|
{
|
|
|
|
|
dst->HL1 = q1->HL1 - q2->HL1; /* HL1 */
|
|
|
|
|
dst->LH1 = q1->LH1 - q2->LH1; /* LH1 */
|
|
|
|
|
dst->HH1 = q1->HH1 - q2->HH1; /* HH1 */
|
|
|
|
|
dst->HL2 = q1->HL2 - q2->HL2; /* HL2 */
|
|
|
|
|
dst->LH2 = q1->LH2 - q2->LH2; /* LH2 */
|
|
|
|
|
dst->HH2 = q1->HH2 - q2->HH2; /* HH2 */
|
|
|
|
|
dst->HL3 = q1->HL3 - q2->HL3; /* HL3 */
|
|
|
|
|
dst->LH3 = q1->LH3 - q2->LH3; /* LH3 */
|
|
|
|
|
dst->HH3 = q1->HH3 - q2->HH3; /* HH3 */
|
|
|
|
|
dst->LL3 = q1->LL3 - q2->LL3; /* LL3 */
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-22 12:19:02 +02:00
|
|
|
static inline BOOL
|
2024-05-29 23:53:33 +02:00
|
|
|
progressive_rfx_quant_lcmp_less_equal(const RFX_COMPONENT_CODEC_QUANT* WINPR_RESTRICT q, int val)
|
2014-08-28 12:14:28 -04:00
|
|
|
{
|
2019-11-06 15:24:51 +01:00
|
|
|
if (q->HL1 > val)
|
|
|
|
|
return FALSE; /* HL1 */
|
2016-04-11 14:14:17 +02:00
|
|
|
|
2019-11-06 15:24:51 +01:00
|
|
|
if (q->LH1 > val)
|
|
|
|
|
return FALSE; /* LH1 */
|
2016-04-11 14:14:17 +02:00
|
|
|
|
2019-11-06 15:24:51 +01:00
|
|
|
if (q->HH1 > val)
|
|
|
|
|
return FALSE; /* HH1 */
|
2016-04-11 14:14:17 +02:00
|
|
|
|
2019-11-06 15:24:51 +01:00
|
|
|
if (q->HL2 > val)
|
|
|
|
|
return FALSE; /* HL2 */
|
2016-04-11 14:14:17 +02:00
|
|
|
|
2019-11-06 15:24:51 +01:00
|
|
|
if (q->LH2 > val)
|
|
|
|
|
return FALSE; /* LH2 */
|
2016-04-11 14:14:17 +02:00
|
|
|
|
2019-11-06 15:24:51 +01:00
|
|
|
if (q->HH2 > val)
|
|
|
|
|
return FALSE; /* HH2 */
|
2016-04-11 14:14:17 +02:00
|
|
|
|
2019-11-06 15:24:51 +01:00
|
|
|
if (q->HL3 > val)
|
|
|
|
|
return FALSE; /* HL3 */
|
2016-04-11 14:14:17 +02:00
|
|
|
|
2019-11-06 15:24:51 +01:00
|
|
|
if (q->LH3 > val)
|
|
|
|
|
return FALSE; /* LH3 */
|
2016-04-11 14:14:17 +02:00
|
|
|
|
2019-11-06 15:24:51 +01:00
|
|
|
if (q->HH3 > val)
|
|
|
|
|
return FALSE; /* HH3 */
|
2016-04-11 14:14:17 +02:00
|
|
|
|
2019-11-06 15:24:51 +01:00
|
|
|
if (q->LL3 > val)
|
|
|
|
|
return FALSE; /* LL3 */
|
2016-04-11 14:14:17 +02:00
|
|
|
|
2014-08-28 12:14:28 -04:00
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-22 12:19:02 +02:00
|
|
|
static inline BOOL
|
2024-05-29 23:53:33 +02:00
|
|
|
progressive_rfx_quant_lcmp_greater_equal(const RFX_COMPONENT_CODEC_QUANT* WINPR_RESTRICT q, int val)
|
2014-08-28 12:14:28 -04:00
|
|
|
{
|
2019-11-06 15:24:51 +01:00
|
|
|
if (q->HL1 < val)
|
|
|
|
|
return FALSE; /* HL1 */
|
2016-04-11 14:14:17 +02:00
|
|
|
|
2019-11-06 15:24:51 +01:00
|
|
|
if (q->LH1 < val)
|
|
|
|
|
return FALSE; /* LH1 */
|
2016-04-11 14:14:17 +02:00
|
|
|
|
2019-11-06 15:24:51 +01:00
|
|
|
if (q->HH1 < val)
|
|
|
|
|
return FALSE; /* HH1 */
|
2016-04-11 14:14:17 +02:00
|
|
|
|
2019-11-06 15:24:51 +01:00
|
|
|
if (q->HL2 < val)
|
|
|
|
|
return FALSE; /* HL2 */
|
2016-04-11 14:14:17 +02:00
|
|
|
|
2019-11-06 15:24:51 +01:00
|
|
|
if (q->LH2 < val)
|
|
|
|
|
return FALSE; /* LH2 */
|
2016-04-11 14:14:17 +02:00
|
|
|
|
2019-11-06 15:24:51 +01:00
|
|
|
if (q->HH2 < val)
|
|
|
|
|
return FALSE; /* HH2 */
|
2016-04-11 14:14:17 +02:00
|
|
|
|
2019-11-06 15:24:51 +01:00
|
|
|
if (q->HL3 < val)
|
|
|
|
|
return FALSE; /* HL3 */
|
2016-04-11 14:14:17 +02:00
|
|
|
|
2019-11-06 15:24:51 +01:00
|
|
|
if (q->LH3 < val)
|
|
|
|
|
return FALSE; /* LH3 */
|
2016-04-11 14:14:17 +02:00
|
|
|
|
2019-11-06 15:24:51 +01:00
|
|
|
if (q->HH3 < val)
|
|
|
|
|
return FALSE; /* HH3 */
|
2016-04-11 14:14:17 +02:00
|
|
|
|
2019-11-06 15:24:51 +01:00
|
|
|
if (q->LL3 < val)
|
|
|
|
|
return FALSE; /* LL3 */
|
2016-04-11 14:14:17 +02:00
|
|
|
|
2014-08-28 12:14:28 -04:00
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-22 12:19:02 +02:00
|
|
|
static inline BOOL
|
2024-05-29 23:53:33 +02:00
|
|
|
progressive_rfx_quant_cmp_equal(const RFX_COMPONENT_CODEC_QUANT* WINPR_RESTRICT q1,
|
|
|
|
|
const RFX_COMPONENT_CODEC_QUANT* WINPR_RESTRICT q2)
|
2014-09-02 13:31:40 -04:00
|
|
|
{
|
2019-11-06 15:24:51 +01:00
|
|
|
if (q1->HL1 != q2->HL1)
|
|
|
|
|
return FALSE; /* HL1 */
|
2016-04-11 14:14:17 +02:00
|
|
|
|
2019-11-06 15:24:51 +01:00
|
|
|
if (q1->LH1 != q2->LH1)
|
|
|
|
|
return FALSE; /* LH1 */
|
2016-04-11 14:14:17 +02:00
|
|
|
|
2019-11-06 15:24:51 +01:00
|
|
|
if (q1->HH1 != q2->HH1)
|
|
|
|
|
return FALSE; /* HH1 */
|
2016-04-11 14:14:17 +02:00
|
|
|
|
2019-11-06 15:24:51 +01:00
|
|
|
if (q1->HL2 != q2->HL2)
|
|
|
|
|
return FALSE; /* HL2 */
|
2016-04-11 14:14:17 +02:00
|
|
|
|
2019-11-06 15:24:51 +01:00
|
|
|
if (q1->LH2 != q2->LH2)
|
|
|
|
|
return FALSE; /* LH2 */
|
2016-04-11 14:14:17 +02:00
|
|
|
|
2019-11-06 15:24:51 +01:00
|
|
|
if (q1->HH2 != q2->HH2)
|
|
|
|
|
return FALSE; /* HH2 */
|
2016-04-11 14:14:17 +02:00
|
|
|
|
2019-11-06 15:24:51 +01:00
|
|
|
if (q1->HL3 != q2->HL3)
|
|
|
|
|
return FALSE; /* HL3 */
|
2016-04-11 14:14:17 +02:00
|
|
|
|
2019-11-06 15:24:51 +01:00
|
|
|
if (q1->LH3 != q2->LH3)
|
|
|
|
|
return FALSE; /* LH3 */
|
2016-04-11 14:14:17 +02:00
|
|
|
|
2019-11-06 15:24:51 +01:00
|
|
|
if (q1->HH3 != q2->HH3)
|
|
|
|
|
return FALSE; /* HH3 */
|
2016-04-11 14:14:17 +02:00
|
|
|
|
2019-11-06 15:24:51 +01:00
|
|
|
if (q1->LL3 != q2->LL3)
|
|
|
|
|
return FALSE; /* LL3 */
|
2016-04-11 14:14:17 +02:00
|
|
|
|
2014-09-02 13:31:40 -04:00
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-22 12:19:02 +02:00
|
|
|
static inline BOOL progressive_set_surface_data(PROGRESSIVE_CONTEXT* WINPR_RESTRICT progressive,
|
2024-05-29 23:53:33 +02:00
|
|
|
UINT16 surfaceId,
|
|
|
|
|
PROGRESSIVE_SURFACE_CONTEXT* WINPR_RESTRICT pData)
|
2014-08-26 16:15:22 -04:00
|
|
|
{
|
2024-01-23 16:49:54 +01:00
|
|
|
ULONG_PTR key = 0;
|
2019-11-06 15:24:51 +01:00
|
|
|
key = ((ULONG_PTR)surfaceId) + 1;
|
2014-08-26 16:15:22 -04:00
|
|
|
|
|
|
|
|
if (pData)
|
2021-06-09 12:31:10 +02:00
|
|
|
return HashTable_Insert(progressive->SurfaceContexts, (void*)key, pData);
|
2014-08-26 16:15:22 -04:00
|
|
|
|
2019-11-06 15:24:51 +01:00
|
|
|
HashTable_Remove(progressive->SurfaceContexts, (void*)key);
|
2017-05-02 18:39:03 +02:00
|
|
|
return TRUE;
|
2014-08-26 16:15:22 -04:00
|
|
|
}
|
|
|
|
|
|
2025-09-22 12:19:02 +02:00
|
|
|
static inline PROGRESSIVE_SURFACE_CONTEXT*
|
2024-05-29 23:53:33 +02:00
|
|
|
progressive_get_surface_data(PROGRESSIVE_CONTEXT* WINPR_RESTRICT progressive, UINT16 surfaceId)
|
2014-08-26 16:15:22 -04:00
|
|
|
{
|
2019-12-10 16:19:20 +01:00
|
|
|
void* key = (void*)(((ULONG_PTR)surfaceId) + 1);
|
|
|
|
|
|
|
|
|
|
if (!progressive)
|
2026-02-26 15:06:27 +01:00
|
|
|
return nullptr;
|
2019-12-10 16:19:20 +01:00
|
|
|
|
2022-04-06 10:10:07 +02:00
|
|
|
return HashTable_GetItemValue(progressive->SurfaceContexts, key);
|
2014-08-26 16:15:22 -04:00
|
|
|
}
|
|
|
|
|
|
2024-05-29 23:53:33 +02:00
|
|
|
static void progressive_tile_free(RFX_PROGRESSIVE_TILE* WINPR_RESTRICT tile)
|
2019-12-10 16:19:20 +01:00
|
|
|
{
|
|
|
|
|
if (tile)
|
|
|
|
|
{
|
2022-05-11 11:28:55 +02:00
|
|
|
winpr_aligned_free(tile->sign);
|
|
|
|
|
winpr_aligned_free(tile->current);
|
|
|
|
|
winpr_aligned_free(tile->data);
|
2023-03-24 12:44:04 +01:00
|
|
|
winpr_aligned_free(tile);
|
2019-12-10 16:19:20 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-06 10:10:07 +02:00
|
|
|
static void progressive_surface_context_free(void* ptr)
|
2019-12-10 16:19:20 +01:00
|
|
|
{
|
2022-04-06 10:10:07 +02:00
|
|
|
PROGRESSIVE_SURFACE_CONTEXT* surface = ptr;
|
2019-12-10 16:19:20 +01:00
|
|
|
|
2022-04-06 10:10:07 +02:00
|
|
|
if (!surface)
|
|
|
|
|
return;
|
|
|
|
|
|
2022-04-28 08:00:39 +02:00
|
|
|
if (surface->tiles)
|
2019-12-10 16:19:20 +01:00
|
|
|
{
|
2024-01-30 10:25:38 +01:00
|
|
|
for (size_t index = 0; index < surface->tilesSize; index++)
|
2022-04-28 08:00:39 +02:00
|
|
|
{
|
2023-03-23 11:15:40 +01:00
|
|
|
RFX_PROGRESSIVE_TILE* tile = surface->tiles[index];
|
2022-04-28 08:00:39 +02:00
|
|
|
progressive_tile_free(tile);
|
|
|
|
|
}
|
2019-12-10 16:19:20 +01:00
|
|
|
}
|
|
|
|
|
|
2024-11-25 15:10:30 +01:00
|
|
|
winpr_aligned_free((void*)surface->tiles);
|
2023-03-23 15:17:00 +01:00
|
|
|
winpr_aligned_free(surface->updatedTileIndices);
|
2023-03-24 12:44:04 +01:00
|
|
|
winpr_aligned_free(surface);
|
2019-12-10 16:19:20 +01:00
|
|
|
}
|
|
|
|
|
|
2025-09-22 12:19:02 +02:00
|
|
|
static inline RFX_PROGRESSIVE_TILE* progressive_tile_new(void)
|
2019-12-10 16:19:20 +01:00
|
|
|
{
|
2023-03-24 12:44:04 +01:00
|
|
|
RFX_PROGRESSIVE_TILE* tile = winpr_aligned_calloc(1, sizeof(RFX_PROGRESSIVE_TILE), 32);
|
2019-12-10 16:19:20 +01:00
|
|
|
if (!tile)
|
2023-03-23 15:17:00 +01:00
|
|
|
goto fail;
|
2019-12-10 16:19:20 +01:00
|
|
|
|
|
|
|
|
tile->width = 64;
|
|
|
|
|
tile->height = 64;
|
|
|
|
|
tile->stride = 4 * tile->width;
|
|
|
|
|
|
2026-01-08 10:32:29 +01:00
|
|
|
{
|
|
|
|
|
const size_t dataLen = 1ull * tile->stride * tile->height;
|
|
|
|
|
tile->data = (BYTE*)winpr_aligned_malloc(dataLen, 16);
|
|
|
|
|
if (!tile->data)
|
|
|
|
|
goto fail;
|
|
|
|
|
memset(tile->data, 0xFF, dataLen);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
const size_t signLen = (8192ULL + 32ULL) * 3ULL;
|
|
|
|
|
tile->sign = (BYTE*)winpr_aligned_malloc(signLen, 16);
|
|
|
|
|
}
|
2023-05-09 23:33:52 +02:00
|
|
|
|
|
|
|
|
if (!tile->sign)
|
|
|
|
|
goto fail;
|
|
|
|
|
|
2026-01-08 10:32:29 +01:00
|
|
|
{
|
|
|
|
|
const size_t currentLen = (8192ULL + 32ULL) * 3ULL;
|
|
|
|
|
tile->current = (BYTE*)winpr_aligned_malloc(currentLen, 16);
|
|
|
|
|
}
|
2023-05-09 23:33:52 +02:00
|
|
|
if (!tile->current)
|
|
|
|
|
goto fail;
|
|
|
|
|
|
|
|
|
|
return tile;
|
|
|
|
|
|
2023-03-23 15:17:00 +01:00
|
|
|
fail:
|
|
|
|
|
progressive_tile_free(tile);
|
2026-02-26 15:06:27 +01:00
|
|
|
return nullptr;
|
2019-12-10 16:19:20 +01:00
|
|
|
}
|
|
|
|
|
|
2025-09-22 12:19:02 +02:00
|
|
|
static inline BOOL
|
2024-06-04 14:32:42 +02:00
|
|
|
progressive_allocate_tile_cache(PROGRESSIVE_SURFACE_CONTEXT* WINPR_RESTRICT surface, size_t min)
|
2022-01-28 09:07:27 +01:00
|
|
|
{
|
2022-04-28 08:00:39 +02:00
|
|
|
size_t oldIndex = 0;
|
2022-01-28 09:07:27 +01:00
|
|
|
|
|
|
|
|
WINPR_ASSERT(surface);
|
|
|
|
|
WINPR_ASSERT(surface->gridSize > 0);
|
|
|
|
|
|
|
|
|
|
if (surface->tiles)
|
2022-04-28 08:00:39 +02:00
|
|
|
{
|
|
|
|
|
oldIndex = surface->gridSize;
|
2023-05-08 09:23:01 +02:00
|
|
|
while (surface->gridSize < min)
|
|
|
|
|
surface->gridSize += 1024;
|
2022-04-28 08:00:39 +02:00
|
|
|
}
|
2022-01-28 09:07:27 +01:00
|
|
|
|
2024-11-25 15:10:30 +01:00
|
|
|
void* tmp = winpr_aligned_recalloc((void*)surface->tiles, surface->gridSize,
|
2023-03-23 15:17:00 +01:00
|
|
|
sizeof(RFX_PROGRESSIVE_TILE*), 32);
|
2023-03-23 11:15:40 +01:00
|
|
|
if (!tmp)
|
|
|
|
|
return FALSE;
|
|
|
|
|
surface->tilesSize = surface->gridSize;
|
2024-11-25 15:10:30 +01:00
|
|
|
surface->tiles = (RFX_PROGRESSIVE_TILE**)tmp;
|
2023-03-23 11:15:40 +01:00
|
|
|
|
2023-06-05 12:16:57 +02:00
|
|
|
for (size_t x = oldIndex; x < surface->tilesSize; x++)
|
2022-01-28 09:07:27 +01:00
|
|
|
{
|
2023-03-23 15:17:00 +01:00
|
|
|
surface->tiles[x] = progressive_tile_new();
|
2023-03-23 11:15:40 +01:00
|
|
|
if (!surface->tiles[x])
|
2023-05-09 23:33:52 +02:00
|
|
|
return FALSE;
|
2023-03-23 15:17:00 +01:00
|
|
|
}
|
2022-04-28 08:00:39 +02:00
|
|
|
|
2023-03-23 15:17:00 +01:00
|
|
|
tmp =
|
|
|
|
|
winpr_aligned_recalloc(surface->updatedTileIndices, surface->gridSize, sizeof(UINT32), 32);
|
2023-03-23 11:15:40 +01:00
|
|
|
if (!tmp)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
surface->updatedTileIndices = tmp;
|
2022-04-28 08:00:39 +02:00
|
|
|
|
2022-01-28 09:07:27 +01:00
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-06 15:24:51 +01:00
|
|
|
static PROGRESSIVE_SURFACE_CONTEXT* progressive_surface_context_new(UINT16 surfaceId, UINT32 width,
|
|
|
|
|
UINT32 height)
|
2014-08-26 16:15:22 -04:00
|
|
|
{
|
2023-03-24 12:44:04 +01:00
|
|
|
PROGRESSIVE_SURFACE_CONTEXT* surface = (PROGRESSIVE_SURFACE_CONTEXT*)winpr_aligned_calloc(
|
|
|
|
|
1, sizeof(PROGRESSIVE_SURFACE_CONTEXT), 32);
|
2014-08-26 16:15:22 -04:00
|
|
|
|
|
|
|
|
if (!surface)
|
2026-02-26 15:06:27 +01:00
|
|
|
return nullptr;
|
2014-09-12 14:57:44 -04:00
|
|
|
|
|
|
|
|
surface->id = surfaceId;
|
|
|
|
|
surface->width = width;
|
|
|
|
|
surface->height = height;
|
2015-05-20 12:26:58 +01:00
|
|
|
surface->gridWidth = (width + (64 - width % 64)) / 64;
|
|
|
|
|
surface->gridHeight = (height + (64 - height % 64)) / 64;
|
2014-09-12 14:57:44 -04:00
|
|
|
surface->gridSize = surface->gridWidth * surface->gridHeight;
|
|
|
|
|
|
2023-05-08 09:23:01 +02:00
|
|
|
if (!progressive_allocate_tile_cache(surface, surface->gridSize))
|
2014-11-17 00:56:56 +01:00
|
|
|
{
|
2022-01-28 09:07:27 +01:00
|
|
|
progressive_surface_context_free(surface);
|
2026-02-26 15:06:27 +01:00
|
|
|
return nullptr;
|
2014-11-17 00:56:56 +01:00
|
|
|
}
|
2014-09-12 14:57:44 -04:00
|
|
|
|
|
|
|
|
return surface;
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-22 12:19:02 +02:00
|
|
|
static inline BOOL
|
2024-06-04 14:32:42 +02:00
|
|
|
progressive_surface_tile_replace(PROGRESSIVE_SURFACE_CONTEXT* WINPR_RESTRICT surface,
|
|
|
|
|
PROGRESSIVE_BLOCK_REGION* WINPR_RESTRICT region,
|
|
|
|
|
const RFX_PROGRESSIVE_TILE* WINPR_RESTRICT tile, BOOL upgrade)
|
2014-09-12 14:57:44 -04:00
|
|
|
{
|
2026-02-26 15:06:27 +01:00
|
|
|
RFX_PROGRESSIVE_TILE* t = nullptr;
|
2014-09-12 14:57:44 -04:00
|
|
|
|
2024-01-23 16:49:54 +01:00
|
|
|
size_t zIdx = 0;
|
2019-12-10 16:19:20 +01:00
|
|
|
if (!surface || !tile)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
zIdx = (tile->yIdx * surface->gridWidth) + tile->xIdx;
|
|
|
|
|
|
2022-04-28 08:00:39 +02:00
|
|
|
if (zIdx >= surface->tilesSize)
|
2014-08-26 16:15:22 -04:00
|
|
|
{
|
2019-12-10 16:19:20 +01:00
|
|
|
WLog_ERR(TAG, "Invalid zIndex %" PRIuz, zIdx);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
2014-08-26 16:15:22 -04:00
|
|
|
|
2023-03-23 11:15:40 +01:00
|
|
|
t = surface->tiles[zIdx];
|
2014-08-26 16:15:22 -04:00
|
|
|
|
2023-03-20 14:51:52 +01:00
|
|
|
t->blockType = tile->blockType;
|
|
|
|
|
t->blockLen = tile->blockLen;
|
|
|
|
|
t->quantIdxY = tile->quantIdxY;
|
|
|
|
|
t->quantIdxCb = tile->quantIdxCb;
|
|
|
|
|
t->quantIdxCr = tile->quantIdxCr;
|
|
|
|
|
t->xIdx = tile->xIdx;
|
|
|
|
|
t->yIdx = tile->yIdx;
|
|
|
|
|
t->flags = tile->flags;
|
|
|
|
|
t->quality = tile->quality;
|
|
|
|
|
t->x = tile->xIdx * t->width;
|
|
|
|
|
t->y = tile->yIdx * t->height;
|
|
|
|
|
|
2019-12-10 16:19:20 +01:00
|
|
|
if (upgrade)
|
|
|
|
|
{
|
|
|
|
|
t->ySrlLen = tile->ySrlLen;
|
|
|
|
|
t->yRawLen = tile->yRawLen;
|
|
|
|
|
t->cbSrlLen = tile->cbSrlLen;
|
|
|
|
|
t->cbRawLen = tile->cbRawLen;
|
|
|
|
|
t->crSrlLen = tile->crSrlLen;
|
|
|
|
|
t->crRawLen = tile->crRawLen;
|
|
|
|
|
t->ySrlData = tile->ySrlData;
|
|
|
|
|
t->yRawData = tile->yRawData;
|
|
|
|
|
t->cbSrlData = tile->cbSrlData;
|
|
|
|
|
t->cbRawData = tile->cbRawData;
|
|
|
|
|
t->crSrlData = tile->crSrlData;
|
|
|
|
|
t->crRawData = tile->crRawData;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
t->yLen = tile->yLen;
|
|
|
|
|
t->cbLen = tile->cbLen;
|
|
|
|
|
t->crLen = tile->crLen;
|
|
|
|
|
t->tailLen = tile->tailLen;
|
|
|
|
|
t->yData = tile->yData;
|
|
|
|
|
t->cbData = tile->cbData;
|
|
|
|
|
t->crData = tile->crData;
|
|
|
|
|
t->tailData = tile->tailData;
|
|
|
|
|
}
|
2014-08-26 16:15:22 -04:00
|
|
|
|
2019-12-10 16:19:20 +01:00
|
|
|
if (region->usedTiles >= region->numTiles)
|
|
|
|
|
{
|
|
|
|
|
WLog_ERR(TAG, "Invalid tile count, only expected %" PRIu16 ", got %" PRIu16,
|
|
|
|
|
region->numTiles, region->usedTiles);
|
|
|
|
|
return FALSE;
|
2014-09-12 14:57:44 -04:00
|
|
|
}
|
2023-05-09 23:33:52 +02:00
|
|
|
|
|
|
|
|
region->tiles[region->usedTiles++] = t;
|
|
|
|
|
if (!t->dirty)
|
2021-02-04 13:01:38 +08:00
|
|
|
{
|
2023-05-09 23:33:52 +02:00
|
|
|
if (surface->numUpdatedTiles >= surface->gridSize)
|
|
|
|
|
{
|
|
|
|
|
if (!progressive_allocate_tile_cache(surface, surface->numUpdatedTiles + 1))
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
surface->updatedTileIndices[surface->numUpdatedTiles++] = (UINT32)zIdx;
|
2021-02-04 13:01:38 +08:00
|
|
|
}
|
2014-08-26 16:15:22 -04:00
|
|
|
|
2023-05-09 23:33:52 +02:00
|
|
|
t->dirty = TRUE;
|
2019-12-10 16:19:20 +01:00
|
|
|
return TRUE;
|
2014-09-12 14:57:44 -04:00
|
|
|
}
|
|
|
|
|
|
2024-05-29 23:53:33 +02:00
|
|
|
INT32 progressive_create_surface_context(PROGRESSIVE_CONTEXT* WINPR_RESTRICT progressive,
|
|
|
|
|
UINT16 surfaceId, UINT32 width, UINT32 height)
|
2014-09-12 14:57:44 -04:00
|
|
|
{
|
2022-04-28 08:00:39 +02:00
|
|
|
PROGRESSIVE_SURFACE_CONTEXT* surface = progressive_get_surface_data(progressive, surfaceId);
|
2014-09-12 14:57:44 -04:00
|
|
|
|
|
|
|
|
if (!surface)
|
|
|
|
|
{
|
|
|
|
|
surface = progressive_surface_context_new(surfaceId, width, height);
|
|
|
|
|
|
|
|
|
|
if (!surface)
|
2014-08-26 16:15:22 -04:00
|
|
|
return -1;
|
|
|
|
|
|
2019-11-06 15:24:51 +01:00
|
|
|
if (!progressive_set_surface_data(progressive, surfaceId, (void*)surface))
|
2017-05-02 18:39:03 +02:00
|
|
|
{
|
|
|
|
|
progressive_surface_context_free(surface);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
2014-08-26 16:15:22 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-29 23:53:33 +02:00
|
|
|
int progressive_delete_surface_context(PROGRESSIVE_CONTEXT* WINPR_RESTRICT progressive,
|
|
|
|
|
UINT16 surfaceId)
|
2014-08-26 16:15:22 -04:00
|
|
|
{
|
2026-02-26 15:06:27 +01:00
|
|
|
progressive_set_surface_data(progressive, surfaceId, nullptr);
|
2014-08-26 16:15:22 -04:00
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2014-08-18 19:12:08 -04:00
|
|
|
/*
|
2019-12-10 16:19:20 +01:00
|
|
|
* Band Offset Dimensions Size
|
2014-08-18 19:12:08 -04:00
|
|
|
*
|
2019-12-10 16:19:20 +01:00
|
|
|
* HL1 0 31x33 1023
|
|
|
|
|
* LH1 1023 33x31 1023
|
|
|
|
|
* HH1 2046 31x31 961
|
2014-08-18 19:12:08 -04:00
|
|
|
*
|
2019-12-10 16:19:20 +01:00
|
|
|
* HL2 3007 16x17 272
|
|
|
|
|
* LH2 3279 17x16 272
|
|
|
|
|
* HH2 3551 16x16 256
|
2014-08-18 19:12:08 -04:00
|
|
|
*
|
2019-12-10 16:19:20 +01:00
|
|
|
* HL3 3807 8x9 72
|
|
|
|
|
* LH3 3879 9x8 72
|
|
|
|
|
* HH3 3951 8x8 64
|
2014-08-18 19:12:08 -04:00
|
|
|
*
|
2019-12-10 16:19:20 +01:00
|
|
|
* LL3 4015 9x9 81
|
2014-08-18 19:12:08 -04:00
|
|
|
*/
|
|
|
|
|
|
2025-03-11 12:00:08 +01:00
|
|
|
static int16_t clampi16(int val)
|
|
|
|
|
{
|
|
|
|
|
if (val < INT16_MIN)
|
|
|
|
|
return INT16_MIN;
|
|
|
|
|
if (val > INT16_MAX)
|
|
|
|
|
return INT16_MAX;
|
|
|
|
|
return (int16_t)val;
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-22 12:19:02 +02:00
|
|
|
static inline void progressive_rfx_idwt_x(const INT16* WINPR_RESTRICT pLowBand, size_t nLowStep,
|
2024-05-29 23:53:33 +02:00
|
|
|
const INT16* WINPR_RESTRICT pHighBand, size_t nHighStep,
|
|
|
|
|
INT16* WINPR_RESTRICT pDstBand, size_t nDstStep,
|
|
|
|
|
size_t nLowCount, size_t nHighCount, size_t nDstCount)
|
2014-08-19 14:48:09 -04:00
|
|
|
{
|
2024-01-23 16:49:54 +01:00
|
|
|
INT16 H1 = 0;
|
|
|
|
|
INT16 X1 = 0;
|
2014-08-19 14:48:09 -04:00
|
|
|
|
2024-01-30 10:25:38 +01:00
|
|
|
for (size_t i = 0; i < nDstCount; i++)
|
2014-08-20 19:12:08 -04:00
|
|
|
{
|
2019-12-10 16:19:20 +01:00
|
|
|
const INT16* pL = pLowBand;
|
|
|
|
|
const INT16* pH = pHighBand;
|
|
|
|
|
INT16* pX = pDstBand;
|
2025-03-11 12:00:08 +01:00
|
|
|
INT16 H0 = *pH++;
|
|
|
|
|
INT16 L0 = *pL++;
|
|
|
|
|
INT16 X0 = clampi16((int32_t)L0 - H0);
|
|
|
|
|
INT16 X2 = clampi16((int32_t)L0 - H0);
|
2014-08-19 14:48:09 -04:00
|
|
|
|
2024-01-30 10:25:38 +01:00
|
|
|
for (size_t j = 0; j < (nHighCount - 1); j++)
|
2014-08-20 19:12:08 -04:00
|
|
|
{
|
|
|
|
|
H1 = *pH;
|
|
|
|
|
pH++;
|
|
|
|
|
L0 = *pL;
|
|
|
|
|
pL++;
|
2025-03-11 12:00:08 +01:00
|
|
|
X2 = clampi16((int32_t)L0 - ((H0 + H1) / 2));
|
|
|
|
|
X1 = clampi16((int32_t)((X0 + X2) / 2) + (2 * H0));
|
2014-08-20 19:12:08 -04:00
|
|
|
pX[0] = X0;
|
|
|
|
|
pX[1] = X1;
|
|
|
|
|
pX += 2;
|
|
|
|
|
X0 = X2;
|
|
|
|
|
H0 = H1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (nLowCount <= (nHighCount + 1))
|
2014-08-19 14:48:09 -04:00
|
|
|
{
|
2014-08-20 19:12:08 -04:00
|
|
|
if (nLowCount <= nHighCount)
|
|
|
|
|
{
|
|
|
|
|
pX[0] = X2;
|
2025-03-11 12:00:08 +01:00
|
|
|
pX[1] = clampi16((int32_t)X2 + (2 * H0));
|
2014-08-20 19:12:08 -04:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
L0 = *pL;
|
|
|
|
|
pL++;
|
2025-03-11 12:00:08 +01:00
|
|
|
X0 = clampi16((int32_t)L0 - H0);
|
2014-08-20 19:12:08 -04:00
|
|
|
pX[0] = X2;
|
2025-03-11 12:00:08 +01:00
|
|
|
pX[1] = clampi16((int32_t)((X0 + X2) / 2) + (2 * H0));
|
2014-08-20 19:12:08 -04:00
|
|
|
pX[2] = X0;
|
|
|
|
|
}
|
2014-08-19 14:48:09 -04:00
|
|
|
}
|
2014-08-20 19:12:08 -04:00
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
L0 = *pL;
|
|
|
|
|
pL++;
|
2025-03-11 12:00:08 +01:00
|
|
|
X0 = clampi16((int32_t)L0 - (H0 / 2));
|
2014-08-20 19:12:08 -04:00
|
|
|
pX[0] = X2;
|
2025-03-11 12:00:08 +01:00
|
|
|
pX[1] = clampi16((int32_t)((X0 + X2) / 2) + (2 * H0));
|
2014-08-20 19:12:08 -04:00
|
|
|
pX[2] = X0;
|
|
|
|
|
L0 = *pL;
|
|
|
|
|
pL++;
|
2025-03-11 12:00:08 +01:00
|
|
|
pX[3] = clampi16((int32_t)(X0 + L0) / 2);
|
2014-08-19 14:48:09 -04:00
|
|
|
}
|
|
|
|
|
|
2014-08-20 19:12:08 -04:00
|
|
|
pLowBand += nLowStep;
|
|
|
|
|
pHighBand += nHighStep;
|
|
|
|
|
pDstBand += nDstStep;
|
2014-08-20 17:16:34 -04:00
|
|
|
}
|
2014-08-20 19:12:08 -04:00
|
|
|
}
|
2014-08-20 17:16:34 -04:00
|
|
|
|
2025-09-22 12:19:02 +02:00
|
|
|
static inline void progressive_rfx_idwt_y(const INT16* WINPR_RESTRICT pLowBand, size_t nLowStep,
|
2024-05-29 23:53:33 +02:00
|
|
|
const INT16* WINPR_RESTRICT pHighBand, size_t nHighStep,
|
|
|
|
|
INT16* WINPR_RESTRICT pDstBand, size_t nDstStep,
|
|
|
|
|
size_t nLowCount, size_t nHighCount, size_t nDstCount)
|
2014-08-20 19:12:08 -04:00
|
|
|
{
|
2024-01-30 10:25:38 +01:00
|
|
|
for (size_t i = 0; i < nDstCount; i++)
|
2014-08-20 17:16:34 -04:00
|
|
|
{
|
2025-03-11 12:00:08 +01:00
|
|
|
INT16 H1 = 0;
|
|
|
|
|
INT16 X1 = 0;
|
2019-12-10 16:19:20 +01:00
|
|
|
const INT16* pL = pLowBand;
|
|
|
|
|
const INT16* pH = pHighBand;
|
|
|
|
|
INT16* pX = pDstBand;
|
2025-03-11 12:00:08 +01:00
|
|
|
INT16 H0 = *pH;
|
2014-08-20 19:12:08 -04:00
|
|
|
pH += nHighStep;
|
2025-03-11 12:00:08 +01:00
|
|
|
INT16 L0 = *pL;
|
2014-08-20 19:12:08 -04:00
|
|
|
pL += nLowStep;
|
2025-03-11 12:00:08 +01:00
|
|
|
int16_t X0 = clampi16((int32_t)L0 - H0);
|
|
|
|
|
int16_t X2 = clampi16((int32_t)L0 - H0);
|
2014-08-20 19:12:08 -04:00
|
|
|
|
2024-01-30 10:25:38 +01:00
|
|
|
for (size_t j = 0; j < (nHighCount - 1); j++)
|
2014-08-20 17:16:34 -04:00
|
|
|
{
|
2014-08-20 19:12:08 -04:00
|
|
|
H1 = *pH;
|
|
|
|
|
pH += nHighStep;
|
|
|
|
|
L0 = *pL;
|
|
|
|
|
pL += nLowStep;
|
2025-03-11 12:00:08 +01:00
|
|
|
X2 = clampi16((int32_t)L0 - ((H0 + H1) / 2));
|
|
|
|
|
X1 = clampi16((int32_t)((X0 + X2) / 2) + (2 * H0));
|
2014-08-20 19:12:08 -04:00
|
|
|
*pX = X0;
|
|
|
|
|
pX += nDstStep;
|
|
|
|
|
*pX = X1;
|
|
|
|
|
pX += nDstStep;
|
|
|
|
|
X0 = X2;
|
|
|
|
|
H0 = H1;
|
|
|
|
|
}
|
2014-08-20 17:16:34 -04:00
|
|
|
|
2014-08-20 19:12:08 -04:00
|
|
|
if (nLowCount <= (nHighCount + 1))
|
2014-08-20 17:16:34 -04:00
|
|
|
{
|
2014-08-20 19:12:08 -04:00
|
|
|
if (nLowCount <= nHighCount)
|
|
|
|
|
{
|
|
|
|
|
*pX = X2;
|
|
|
|
|
pX += nDstStep;
|
2025-03-11 12:00:08 +01:00
|
|
|
*pX = clampi16((int32_t)X2 + (2 * H0));
|
2014-08-20 19:12:08 -04:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
L0 = *pL;
|
2025-03-11 12:00:08 +01:00
|
|
|
X0 = clampi16((int32_t)L0 - H0);
|
2014-08-20 19:12:08 -04:00
|
|
|
*pX = X2;
|
|
|
|
|
pX += nDstStep;
|
2025-03-11 12:00:08 +01:00
|
|
|
*pX = clampi16((int32_t)((X0 + X2) / 2) + (2 * H0));
|
2014-08-20 19:12:08 -04:00
|
|
|
pX += nDstStep;
|
|
|
|
|
*pX = X0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
L0 = *pL;
|
|
|
|
|
pL += nLowStep;
|
2025-03-11 12:00:08 +01:00
|
|
|
X0 = clampi16((int32_t)L0 - (H0 / 2));
|
2014-08-20 19:12:08 -04:00
|
|
|
*pX = X2;
|
|
|
|
|
pX += nDstStep;
|
2025-03-11 12:00:08 +01:00
|
|
|
*pX = clampi16((int32_t)((X0 + X2) / 2) + (2 * H0));
|
2014-08-20 19:12:08 -04:00
|
|
|
pX += nDstStep;
|
|
|
|
|
*pX = X0;
|
|
|
|
|
pX += nDstStep;
|
|
|
|
|
L0 = *pL;
|
2025-03-11 12:00:08 +01:00
|
|
|
*pX = clampi16((int32_t)(X0 + L0) / 2);
|
2014-08-20 17:16:34 -04:00
|
|
|
}
|
2014-08-19 14:48:09 -04:00
|
|
|
|
2014-08-21 19:02:26 -04:00
|
|
|
pLowBand++;
|
|
|
|
|
pHighBand++;
|
|
|
|
|
pDstBand++;
|
2014-08-19 14:48:09 -04:00
|
|
|
}
|
2014-08-20 19:12:08 -04:00
|
|
|
}
|
2014-08-19 14:48:09 -04:00
|
|
|
|
2025-09-22 12:19:02 +02:00
|
|
|
static inline size_t progressive_rfx_get_band_l_count(size_t level)
|
2014-08-20 19:12:08 -04:00
|
|
|
{
|
2014-08-21 16:05:39 -04:00
|
|
|
return (64 >> level) + 1;
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-22 12:19:02 +02:00
|
|
|
static inline size_t progressive_rfx_get_band_h_count(size_t level)
|
2014-08-21 16:05:39 -04:00
|
|
|
{
|
|
|
|
|
if (level == 1)
|
|
|
|
|
return (64 >> 1) - 1;
|
|
|
|
|
else
|
|
|
|
|
return (64 + (1 << (level - 1))) >> level;
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-22 12:19:02 +02:00
|
|
|
static inline void progressive_rfx_dwt_2d_decode_block(INT16* WINPR_RESTRICT buffer,
|
2024-05-29 23:53:33 +02:00
|
|
|
INT16* WINPR_RESTRICT temp, size_t level)
|
2014-08-21 16:05:39 -04:00
|
|
|
{
|
2024-01-23 16:49:54 +01:00
|
|
|
size_t nDstStepX = 0;
|
|
|
|
|
size_t nDstStepY = 0;
|
2026-02-26 15:06:27 +01:00
|
|
|
const INT16* WINPR_RESTRICT HL = nullptr;
|
|
|
|
|
const INT16* WINPR_RESTRICT LH = nullptr;
|
|
|
|
|
const INT16* WINPR_RESTRICT HH = nullptr;
|
|
|
|
|
INT16* WINPR_RESTRICT LL = nullptr;
|
|
|
|
|
INT16* WINPR_RESTRICT L = nullptr;
|
|
|
|
|
INT16* WINPR_RESTRICT H = nullptr;
|
|
|
|
|
INT16* WINPR_RESTRICT LLx = nullptr;
|
2019-12-10 16:19:20 +01:00
|
|
|
|
|
|
|
|
const size_t nBandL = progressive_rfx_get_band_l_count(level);
|
|
|
|
|
const size_t nBandH = progressive_rfx_get_band_h_count(level);
|
|
|
|
|
size_t offset = 0;
|
2019-12-16 08:34:42 +01:00
|
|
|
|
2014-08-21 16:05:39 -04:00
|
|
|
HL = &buffer[offset];
|
|
|
|
|
offset += (nBandH * nBandL);
|
|
|
|
|
LH = &buffer[offset];
|
|
|
|
|
offset += (nBandL * nBandH);
|
|
|
|
|
HH = &buffer[offset];
|
|
|
|
|
offset += (nBandH * nBandH);
|
|
|
|
|
LL = &buffer[offset];
|
2014-08-21 17:14:10 -04:00
|
|
|
nDstStepX = (nBandL + nBandH);
|
|
|
|
|
nDstStepY = (nBandL + nBandH);
|
2014-08-26 14:36:33 -04:00
|
|
|
offset = 0;
|
|
|
|
|
L = &temp[offset];
|
|
|
|
|
offset += (nBandL * nDstStepX);
|
|
|
|
|
H = &temp[offset];
|
|
|
|
|
LLx = &buffer[0];
|
2019-12-10 16:19:20 +01:00
|
|
|
|
2014-08-20 19:12:08 -04:00
|
|
|
/* horizontal (LL + HL -> L) */
|
2019-12-10 16:19:20 +01:00
|
|
|
progressive_rfx_idwt_x(LL, nBandL, HL, nBandH, L, nDstStepX, nBandL, nBandH, nBandL);
|
|
|
|
|
|
2014-08-20 19:12:08 -04:00
|
|
|
/* horizontal (LH + HH -> H) */
|
2019-12-10 16:19:20 +01:00
|
|
|
progressive_rfx_idwt_x(LH, nBandL, HH, nBandH, H, nDstStepX, nBandL, nBandH, nBandH);
|
|
|
|
|
|
2014-08-20 19:12:08 -04:00
|
|
|
/* vertical (L + H -> LL) */
|
2019-12-10 16:19:20 +01:00
|
|
|
progressive_rfx_idwt_y(L, nDstStepX, H, nDstStepX, LLx, nDstStepY, nBandL, nBandH,
|
|
|
|
|
nBandL + nBandH);
|
2014-08-19 14:48:09 -04:00
|
|
|
}
|
|
|
|
|
|
2026-02-25 16:05:02 +01:00
|
|
|
void rfx_dwt_2d_extrapolate_decode(INT16* WINPR_RESTRICT buffer, INT16* WINPR_RESTRICT dwt_buffer)
|
2023-08-14 02:37:11 -04:00
|
|
|
{
|
|
|
|
|
WINPR_ASSERT(buffer);
|
2026-02-25 16:05:02 +01:00
|
|
|
WINPR_ASSERT(dwt_buffer);
|
|
|
|
|
progressive_rfx_dwt_2d_decode_block(&buffer[3807], dwt_buffer, 3);
|
|
|
|
|
progressive_rfx_dwt_2d_decode_block(&buffer[3007], dwt_buffer, 2);
|
|
|
|
|
progressive_rfx_dwt_2d_decode_block(&buffer[0], dwt_buffer, 1);
|
2023-08-14 02:37:11 -04:00
|
|
|
}
|
|
|
|
|
|
2025-09-22 12:19:02 +02:00
|
|
|
static inline int progressive_rfx_dwt_2d_decode(PROGRESSIVE_CONTEXT* WINPR_RESTRICT progressive,
|
2024-05-29 23:53:33 +02:00
|
|
|
INT16* WINPR_RESTRICT buffer,
|
|
|
|
|
INT16* WINPR_RESTRICT current, BOOL coeffDiff,
|
|
|
|
|
BOOL extrapolate, BOOL reverse)
|
2014-08-19 14:48:09 -04:00
|
|
|
{
|
2014-08-26 14:36:33 -04:00
|
|
|
const primitives_t* prims = primitives_get();
|
2019-12-16 08:34:42 +01:00
|
|
|
|
|
|
|
|
if (!progressive || !buffer || !current)
|
|
|
|
|
return -1;
|
2014-08-26 14:36:33 -04:00
|
|
|
|
2025-03-11 11:29:18 +01:00
|
|
|
const uint32_t belements = 4096;
|
|
|
|
|
const uint32_t bsize = belements * sizeof(INT16);
|
2019-12-16 08:34:42 +01:00
|
|
|
if (reverse)
|
2024-06-07 11:56:44 +02:00
|
|
|
memcpy(buffer, current, bsize);
|
|
|
|
|
else if (!coeffDiff)
|
|
|
|
|
memcpy(current, buffer, bsize);
|
2019-12-16 08:34:42 +01:00
|
|
|
else
|
2026-02-16 08:18:37 +01:00
|
|
|
{
|
|
|
|
|
const pstatus_t rc = prims->add_16s_inplace(buffer, current, belements);
|
|
|
|
|
if (rc != PRIMITIVES_SUCCESS)
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
2023-09-15 07:57:45 +02:00
|
|
|
|
|
|
|
|
INT16* temp = (INT16*)BufferPool_Take(progressive->bufferPool, -1); /* DWT buffer */
|
|
|
|
|
|
2019-12-16 08:34:42 +01:00
|
|
|
if (!temp)
|
|
|
|
|
return -2;
|
2020-12-15 09:58:37 +01:00
|
|
|
|
2019-12-16 08:34:42 +01:00
|
|
|
if (!extrapolate)
|
|
|
|
|
{
|
2020-12-15 09:58:37 +01:00
|
|
|
progressive->rfx_context->dwt_2d_decode(buffer, temp);
|
2019-12-16 08:34:42 +01:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2023-08-14 02:37:11 -04:00
|
|
|
WINPR_ASSERT(progressive->rfx_context->dwt_2d_extrapolate_decode);
|
|
|
|
|
progressive->rfx_context->dwt_2d_extrapolate_decode(buffer, temp);
|
2019-12-16 08:34:42 +01:00
|
|
|
}
|
|
|
|
|
BufferPool_Return(progressive->bufferPool, temp);
|
|
|
|
|
return 1;
|
2014-08-19 14:48:09 -04:00
|
|
|
}
|
|
|
|
|
|
2026-02-16 10:57:57 +01:00
|
|
|
static inline BOOL progressive_rfx_decode_block(const primitives_t* prims,
|
2024-05-29 23:53:33 +02:00
|
|
|
INT16* WINPR_RESTRICT buffer, UINT32 length,
|
|
|
|
|
UINT32 shift)
|
2014-08-28 15:14:01 -04:00
|
|
|
{
|
2026-02-16 10:57:57 +01:00
|
|
|
if (shift == 0)
|
|
|
|
|
return TRUE;
|
2014-08-28 15:14:01 -04:00
|
|
|
|
2026-02-16 10:57:57 +01:00
|
|
|
return prims->lShiftC_16s_inplace(buffer, shift, length) == PRIMITIVES_SUCCESS;
|
2014-08-28 15:14:01 -04:00
|
|
|
}
|
|
|
|
|
|
2025-09-22 12:19:02 +02:00
|
|
|
static inline int
|
2025-02-13 15:29:10 +01:00
|
|
|
progressive_rfx_decode_component(PROGRESSIVE_CONTEXT* WINPR_RESTRICT progressive,
|
|
|
|
|
const RFX_COMPONENT_CODEC_QUANT* WINPR_RESTRICT shift,
|
|
|
|
|
const BYTE* WINPR_RESTRICT data, UINT32 length,
|
|
|
|
|
INT16* WINPR_RESTRICT buffer, INT16* WINPR_RESTRICT current,
|
|
|
|
|
INT16* WINPR_RESTRICT sign, BOOL coeffDiff,
|
|
|
|
|
WINPR_ATTR_UNUSED BOOL subbandDiff, BOOL extrapolate)
|
2014-08-06 10:23:14 -04:00
|
|
|
{
|
2024-01-23 16:49:54 +01:00
|
|
|
int status = 0;
|
2014-08-18 19:12:08 -04:00
|
|
|
const primitives_t* prims = primitives_get();
|
2019-12-16 08:34:42 +01:00
|
|
|
|
2020-12-15 09:58:37 +01:00
|
|
|
status = progressive->rfx_context->rlgr_decode(RLGR1, data, length, buffer, 4096);
|
2014-08-06 10:23:14 -04:00
|
|
|
|
|
|
|
|
if (status < 0)
|
|
|
|
|
return status;
|
|
|
|
|
|
2024-08-26 16:33:59 +02:00
|
|
|
CopyMemory(sign, buffer, 4096ULL * 2ULL);
|
codec/progressive: Fix wrong usage of subband diffing flag (#8076)
Currently, all Calista Progressive encoded streams contain tile
artifacts, when the RFX_SUBBAND_DIFFING is used, but not the
RFX_DWT_REDUCE_EXTRAPOLATE flag.
The reason is the wrong usage of the context and tile flags.
The RFX_SUBBAND_DIFFING flag should have no actual impact on the
decoder itself.
Especially, it does not affect the band sizes within a 64x64 tile.
The RFX_DWT_REDUCE_EXTRAPOLATE flag, on the other hand, MUST have an
effect on the band sizes.
However, FreeRDP currently uses the RFX_SUBBAND_DIFFING flag when
decoding a component to determine whether the Reduce-Extrapolate method
is used, resulting in tile artifacts, when that method was actually not
used.
The current behaviour did not result in tile artifacts with the MS
Windows RDS, as that server always sets both flags.
So, fix this issue by using the correct flag, when decoding a tile.
2022-07-15 08:32:33 +02:00
|
|
|
if (!extrapolate)
|
2020-12-15 09:58:37 +01:00
|
|
|
{
|
|
|
|
|
rfx_differential_decode(buffer + 4032, 64);
|
2026-02-16 10:57:57 +01:00
|
|
|
if (!progressive_rfx_decode_block(prims, &buffer[0], 1024, shift->HL1)) /* HL1 */
|
|
|
|
|
return -1;
|
|
|
|
|
if (!progressive_rfx_decode_block(prims, &buffer[1024], 1024, shift->LH1)) /* LH1 */
|
|
|
|
|
return -1;
|
|
|
|
|
if (!progressive_rfx_decode_block(prims, &buffer[2048], 1024, shift->HH1)) /* HH1 */
|
|
|
|
|
return -1;
|
|
|
|
|
if (!progressive_rfx_decode_block(prims, &buffer[3072], 256, shift->HL2)) /* HL2 */
|
|
|
|
|
return -1;
|
|
|
|
|
if (!progressive_rfx_decode_block(prims, &buffer[3328], 256, shift->LH2)) /* LH2 */
|
|
|
|
|
return -1;
|
|
|
|
|
if (!progressive_rfx_decode_block(prims, &buffer[3584], 256, shift->HH2)) /* HH2 */
|
|
|
|
|
return -1;
|
|
|
|
|
if (!progressive_rfx_decode_block(prims, &buffer[3840], 64, shift->HL3)) /* HL3 */
|
|
|
|
|
return -1;
|
|
|
|
|
if (!progressive_rfx_decode_block(prims, &buffer[3904], 64, shift->LH3)) /* LH3 */
|
|
|
|
|
return -1;
|
|
|
|
|
if (!progressive_rfx_decode_block(prims, &buffer[3968], 64, shift->HH3)) /* HH3 */
|
|
|
|
|
return -1;
|
|
|
|
|
if (!progressive_rfx_decode_block(prims, &buffer[4032], 64, shift->LL3)) /* LL3 */
|
|
|
|
|
return -1;
|
2020-12-15 09:58:37 +01:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2026-02-16 10:57:57 +01:00
|
|
|
if (!progressive_rfx_decode_block(prims, &buffer[0], 1023, shift->HL1)) /* HL1 */
|
|
|
|
|
return -1;
|
|
|
|
|
if (!progressive_rfx_decode_block(prims, &buffer[1023], 1023, shift->LH1)) /* LH1 */
|
|
|
|
|
return -1;
|
|
|
|
|
if (!progressive_rfx_decode_block(prims, &buffer[2046], 961, shift->HH1)) /* HH1 */
|
|
|
|
|
return -1;
|
|
|
|
|
if (!progressive_rfx_decode_block(prims, &buffer[3007], 272, shift->HL2)) /* HL2 */
|
|
|
|
|
return -1;
|
|
|
|
|
if (!progressive_rfx_decode_block(prims, &buffer[3279], 272, shift->LH2)) /* LH2 */
|
|
|
|
|
return -1;
|
|
|
|
|
if (!progressive_rfx_decode_block(prims, &buffer[3551], 256, shift->HH2)) /* HH2 */
|
|
|
|
|
return -1;
|
|
|
|
|
if (!progressive_rfx_decode_block(prims, &buffer[3807], 72, shift->HL3)) /* HL3 */
|
|
|
|
|
return -1;
|
|
|
|
|
if (!progressive_rfx_decode_block(prims, &buffer[3879], 72, shift->LH3)) /* LH3 */
|
|
|
|
|
return -1;
|
|
|
|
|
if (!progressive_rfx_decode_block(prims, &buffer[3951], 64, shift->HH3)) /* HH3 */
|
|
|
|
|
return -1;
|
2020-12-15 09:58:37 +01:00
|
|
|
rfx_differential_decode(&buffer[4015], 81); /* LL3 */
|
2026-02-16 10:57:57 +01:00
|
|
|
if (!progressive_rfx_decode_block(prims, &buffer[4015], 81, shift->LL3)) /* LL3 */
|
|
|
|
|
return -1;
|
2020-12-15 09:58:37 +01:00
|
|
|
}
|
2019-12-16 08:34:42 +01:00
|
|
|
return progressive_rfx_dwt_2d_decode(progressive, buffer, current, coeffDiff, extrapolate,
|
|
|
|
|
FALSE);
|
2014-08-06 10:23:14 -04:00
|
|
|
}
|
|
|
|
|
|
2025-09-22 12:19:02 +02:00
|
|
|
static inline int
|
2024-05-29 23:53:33 +02:00
|
|
|
progressive_decompress_tile_first(PROGRESSIVE_CONTEXT* WINPR_RESTRICT progressive,
|
|
|
|
|
RFX_PROGRESSIVE_TILE* WINPR_RESTRICT tile,
|
|
|
|
|
PROGRESSIVE_BLOCK_REGION* WINPR_RESTRICT region,
|
|
|
|
|
const PROGRESSIVE_BLOCK_CONTEXT* WINPR_RESTRICT context)
|
2014-08-28 12:14:28 -04:00
|
|
|
{
|
2024-01-23 16:49:54 +01:00
|
|
|
int rc = 0;
|
|
|
|
|
BOOL diff = 0;
|
|
|
|
|
BOOL sub = 0;
|
|
|
|
|
BOOL extrapolate = 0;
|
2026-02-26 15:06:27 +01:00
|
|
|
BYTE* pBuffer = nullptr;
|
2014-08-28 15:14:01 -04:00
|
|
|
INT16* pSign[3];
|
2014-08-28 12:14:28 -04:00
|
|
|
INT16* pSrcDst[3];
|
|
|
|
|
INT16* pCurrent[3];
|
2026-02-24 20:18:25 +01:00
|
|
|
RFX_COMPONENT_CODEC_QUANT shiftY = WINPR_C_ARRAY_INIT;
|
|
|
|
|
RFX_COMPONENT_CODEC_QUANT shiftCb = WINPR_C_ARRAY_INIT;
|
|
|
|
|
RFX_COMPONENT_CODEC_QUANT shiftCr = WINPR_C_ARRAY_INIT;
|
2026-02-26 15:06:27 +01:00
|
|
|
RFX_COMPONENT_CODEC_QUANT* quantY = nullptr;
|
|
|
|
|
RFX_COMPONENT_CODEC_QUANT* quantCb = nullptr;
|
|
|
|
|
RFX_COMPONENT_CODEC_QUANT* quantCr = nullptr;
|
|
|
|
|
RFX_COMPONENT_CODEC_QUANT* quantProgY = nullptr;
|
|
|
|
|
RFX_COMPONENT_CODEC_QUANT* quantProgCb = nullptr;
|
|
|
|
|
RFX_COMPONENT_CODEC_QUANT* quantProgCr = nullptr;
|
|
|
|
|
RFX_PROGRESSIVE_CODEC_QUANT* quantProgVal = nullptr;
|
2014-08-28 12:14:28 -04:00
|
|
|
static const prim_size_t roi_64x64 = { 64, 64 };
|
|
|
|
|
const primitives_t* prims = primitives_get();
|
2017-05-02 18:39:03 +02:00
|
|
|
|
2014-08-28 12:14:28 -04:00
|
|
|
tile->pass = 1;
|
|
|
|
|
diff = tile->flags & RFX_TILE_DIFFERENCE;
|
2019-12-10 16:19:20 +01:00
|
|
|
sub = context->flags & RFX_SUBBAND_DIFFING;
|
|
|
|
|
extrapolate = region->flags & RFX_DWT_REDUCE_EXTRAPOLATE;
|
|
|
|
|
|
2022-12-13 11:18:11 +01:00
|
|
|
#if defined(WITH_DEBUG_CODECS)
|
2017-01-18 15:25:24 +01:00
|
|
|
WLog_Print(progressive->log, WLOG_DEBUG,
|
2019-11-06 15:24:51 +01:00
|
|
|
"ProgressiveTile%s: quantIdx Y: %" PRIu8 " Cb: %" PRIu8 " Cr: %" PRIu8
|
|
|
|
|
" xIdx: %" PRIu16 " yIdx: %" PRIu16 " flags: 0x%02" PRIX8 " quality: %" PRIu8
|
|
|
|
|
" yLen: %" PRIu16 " cbLen: %" PRIu16 " crLen: %" PRIu16 " tailLen: %" PRIu16 "",
|
2017-01-18 15:25:24 +01:00
|
|
|
(tile->blockType == PROGRESSIVE_WBT_TILE_FIRST) ? "First" : "Simple",
|
2019-11-06 15:24:51 +01:00
|
|
|
tile->quantIdxY, tile->quantIdxCb, tile->quantIdxCr, tile->xIdx, tile->yIdx,
|
|
|
|
|
tile->flags, tile->quality, tile->yLen, tile->cbLen, tile->crLen, tile->tailLen);
|
2022-12-13 11:18:11 +01:00
|
|
|
#endif
|
2014-08-28 12:14:28 -04:00
|
|
|
|
|
|
|
|
if (tile->quantIdxY >= region->numQuant)
|
2019-12-10 16:19:20 +01:00
|
|
|
{
|
|
|
|
|
WLog_ERR(TAG, "quantIdxY %" PRIu8 " > numQuant %" PRIu8, tile->quantIdxY, region->numQuant);
|
2014-08-28 12:14:28 -04:00
|
|
|
return -1;
|
2019-12-10 16:19:20 +01:00
|
|
|
}
|
2014-08-28 12:14:28 -04:00
|
|
|
|
|
|
|
|
quantY = &(region->quantVals[tile->quantIdxY]);
|
|
|
|
|
|
|
|
|
|
if (tile->quantIdxCb >= region->numQuant)
|
2019-12-10 16:19:20 +01:00
|
|
|
{
|
|
|
|
|
WLog_ERR(TAG, "quantIdxCb %" PRIu8 " > numQuant %" PRIu8, tile->quantIdxCb,
|
|
|
|
|
region->numQuant);
|
2014-08-28 12:14:28 -04:00
|
|
|
return -1;
|
2019-12-10 16:19:20 +01:00
|
|
|
}
|
2014-08-28 12:14:28 -04:00
|
|
|
|
|
|
|
|
quantCb = &(region->quantVals[tile->quantIdxCb]);
|
|
|
|
|
|
|
|
|
|
if (tile->quantIdxCr >= region->numQuant)
|
2019-12-10 16:19:20 +01:00
|
|
|
{
|
|
|
|
|
WLog_ERR(TAG, "quantIdxCr %" PRIu8 " > numQuant %" PRIu8, tile->quantIdxCr,
|
|
|
|
|
region->numQuant);
|
2014-08-28 12:14:28 -04:00
|
|
|
return -1;
|
2019-12-10 16:19:20 +01:00
|
|
|
}
|
2014-08-28 12:14:28 -04:00
|
|
|
|
|
|
|
|
quantCr = &(region->quantVals[tile->quantIdxCr]);
|
|
|
|
|
|
|
|
|
|
if (tile->quality == 0xFF)
|
|
|
|
|
{
|
|
|
|
|
quantProgVal = &(progressive->quantProgValFull);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (tile->quality >= region->numProgQuant)
|
2019-12-10 16:19:20 +01:00
|
|
|
{
|
|
|
|
|
WLog_ERR(TAG, "quality %" PRIu8 " > numProgQuant %" PRIu8, tile->quality,
|
|
|
|
|
region->numProgQuant);
|
2014-08-28 12:14:28 -04:00
|
|
|
return -1;
|
2019-12-10 16:19:20 +01:00
|
|
|
}
|
2014-08-28 12:14:28 -04:00
|
|
|
|
|
|
|
|
quantProgVal = &(region->quantProgVals[tile->quality]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
quantProgY = &(quantProgVal->yQuantValues);
|
|
|
|
|
quantProgCb = &(quantProgVal->cbQuantValues);
|
|
|
|
|
quantProgCr = &(quantProgVal->crQuantValues);
|
2017-05-02 18:39:03 +02:00
|
|
|
|
2019-12-10 16:19:20 +01:00
|
|
|
tile->yQuant = *quantY;
|
|
|
|
|
tile->cbQuant = *quantCb;
|
|
|
|
|
tile->crQuant = *quantCr;
|
|
|
|
|
tile->yProgQuant = *quantProgY;
|
|
|
|
|
tile->cbProgQuant = *quantProgCb;
|
|
|
|
|
tile->crProgQuant = *quantProgCr;
|
|
|
|
|
|
2014-09-02 13:31:40 -04:00
|
|
|
progressive_rfx_quant_add(quantY, quantProgY, &(tile->yBitPos));
|
|
|
|
|
progressive_rfx_quant_add(quantCb, quantProgCb, &(tile->cbBitPos));
|
|
|
|
|
progressive_rfx_quant_add(quantCr, quantProgCr, &(tile->crBitPos));
|
2014-08-28 12:14:28 -04:00
|
|
|
progressive_rfx_quant_add(quantY, quantProgY, &shiftY);
|
|
|
|
|
progressive_rfx_quant_lsub(&shiftY, 1); /* -6 + 5 = -1 */
|
|
|
|
|
progressive_rfx_quant_add(quantCb, quantProgCb, &shiftCb);
|
|
|
|
|
progressive_rfx_quant_lsub(&shiftCb, 1); /* -6 + 5 = -1 */
|
|
|
|
|
progressive_rfx_quant_add(quantCr, quantProgCr, &shiftCr);
|
|
|
|
|
progressive_rfx_quant_lsub(&shiftCr, 1); /* -6 + 5 = -1 */
|
|
|
|
|
|
2024-08-29 11:11:11 +02:00
|
|
|
pSign[0] = (INT16*)((&tile->sign[((8192 + 32) * 0) + 16])); /* Y/R buffer */
|
|
|
|
|
pSign[1] = (INT16*)((&tile->sign[((8192 + 32) * 1) + 16])); /* Cb/G buffer */
|
|
|
|
|
pSign[2] = (INT16*)((&tile->sign[((8192 + 32) * 2) + 16])); /* Cr/B buffer */
|
2017-05-02 18:39:03 +02:00
|
|
|
|
2024-08-29 11:11:11 +02:00
|
|
|
pCurrent[0] = (INT16*)((&tile->current[((8192 + 32) * 0) + 16])); /* Y/R buffer */
|
|
|
|
|
pCurrent[1] = (INT16*)((&tile->current[((8192 + 32) * 1) + 16])); /* Cb/G buffer */
|
|
|
|
|
pCurrent[2] = (INT16*)((&tile->current[((8192 + 32) * 2) + 16])); /* Cr/B buffer */
|
2017-05-02 18:39:03 +02:00
|
|
|
|
2019-11-06 15:24:51 +01:00
|
|
|
pBuffer = (BYTE*)BufferPool_Take(progressive->bufferPool, -1);
|
2024-08-29 11:11:11 +02:00
|
|
|
pSrcDst[0] = (INT16*)((&pBuffer[((8192 + 32) * 0) + 16])); /* Y/R buffer */
|
|
|
|
|
pSrcDst[1] = (INT16*)((&pBuffer[((8192 + 32) * 1) + 16])); /* Cb/G buffer */
|
|
|
|
|
pSrcDst[2] = (INT16*)((&pBuffer[((8192 + 32) * 2) + 16])); /* Cr/B buffer */
|
2017-05-02 18:39:03 +02:00
|
|
|
|
2019-12-10 16:19:20 +01:00
|
|
|
rc = progressive_rfx_decode_component(progressive, &shiftY, tile->yData, tile->yLen, pSrcDst[0],
|
|
|
|
|
pCurrent[0], pSign[0], diff, sub, extrapolate); /* Y */
|
|
|
|
|
if (rc < 0)
|
|
|
|
|
goto fail;
|
|
|
|
|
rc = progressive_rfx_decode_component(progressive, &shiftCb, tile->cbData, tile->cbLen,
|
|
|
|
|
pSrcDst[1], pCurrent[1], pSign[1], diff, sub,
|
|
|
|
|
extrapolate); /* Cb */
|
|
|
|
|
if (rc < 0)
|
|
|
|
|
goto fail;
|
|
|
|
|
rc = progressive_rfx_decode_component(progressive, &shiftCr, tile->crData, tile->crLen,
|
|
|
|
|
pSrcDst[2], pCurrent[2], pSign[2], diff, sub,
|
|
|
|
|
extrapolate); /* Cr */
|
|
|
|
|
if (rc < 0)
|
|
|
|
|
goto fail;
|
|
|
|
|
|
2026-01-08 10:32:29 +01:00
|
|
|
{
|
|
|
|
|
const INT16** ptr = WINPR_REINTERPRET_CAST(pSrcDst, INT16**, const INT16**);
|
|
|
|
|
rc = prims->yCbCrToRGB_16s8u_P3AC4R(ptr, 64 * 2, tile->data, tile->stride,
|
|
|
|
|
progressive->format, &roi_64x64);
|
|
|
|
|
}
|
2019-12-10 16:19:20 +01:00
|
|
|
fail:
|
2014-08-28 12:14:28 -04:00
|
|
|
BufferPool_Return(progressive->bufferPool, pBuffer);
|
2019-12-10 16:19:20 +01:00
|
|
|
return rc;
|
2014-08-28 12:14:28 -04:00
|
|
|
}
|
|
|
|
|
|
2025-09-22 12:19:02 +02:00
|
|
|
static inline INT16 progressive_rfx_srl_read(RFX_PROGRESSIVE_UPGRADE_STATE* WINPR_RESTRICT state,
|
2024-05-29 23:53:33 +02:00
|
|
|
UINT32 numBits)
|
2014-08-28 12:14:28 -04:00
|
|
|
{
|
2024-08-23 11:57:26 +02:00
|
|
|
WINPR_ASSERT(state);
|
|
|
|
|
|
2014-08-28 12:14:28 -04:00
|
|
|
wBitStream* bs = state->srl;
|
2024-08-23 11:57:26 +02:00
|
|
|
WINPR_ASSERT(bs);
|
2014-08-28 12:14:28 -04:00
|
|
|
|
|
|
|
|
if (state->nz)
|
|
|
|
|
{
|
|
|
|
|
state->nz--;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-23 11:57:26 +02:00
|
|
|
const UINT32 k = state->kp / 8;
|
2014-09-02 18:15:36 -04:00
|
|
|
|
2014-08-28 12:14:28 -04:00
|
|
|
if (!state->mode)
|
|
|
|
|
{
|
|
|
|
|
/* zero encoding */
|
2024-08-23 11:57:26 +02:00
|
|
|
const UINT32 bit = (bs->accumulator & 0x80000000) ? 1 : 0;
|
2014-08-28 12:14:28 -04:00
|
|
|
BitStream_Shift(bs, 1);
|
|
|
|
|
|
|
|
|
|
if (!bit)
|
|
|
|
|
{
|
|
|
|
|
/* '0' bit, nz >= (1 << k), nz = (1 << k) */
|
2014-09-02 18:15:36 -04:00
|
|
|
state->nz = (1 << k);
|
2014-08-28 12:14:28 -04:00
|
|
|
state->kp += 4;
|
|
|
|
|
|
|
|
|
|
if (state->kp > 80)
|
|
|
|
|
state->kp = 80;
|
|
|
|
|
|
|
|
|
|
state->nz--;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2014-09-02 18:15:36 -04:00
|
|
|
else
|
2014-08-28 15:14:01 -04:00
|
|
|
{
|
2014-09-02 18:15:36 -04:00
|
|
|
/* '1' bit, nz < (1 << k), nz = next k bits */
|
|
|
|
|
state->nz = 0;
|
2014-08-28 15:14:01 -04:00
|
|
|
state->mode = 1; /* unary encoding is next */
|
2014-09-02 18:15:36 -04:00
|
|
|
|
|
|
|
|
if (k)
|
|
|
|
|
{
|
|
|
|
|
bs->mask = ((1 << k) - 1);
|
2024-12-19 14:45:06 +01:00
|
|
|
state->nz =
|
|
|
|
|
WINPR_ASSERTING_INT_CAST(int16_t, ((bs->accumulator >> (32u - k)) & bs->mask));
|
2014-09-02 18:15:36 -04:00
|
|
|
BitStream_Shift(bs, k);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (state->nz)
|
|
|
|
|
{
|
|
|
|
|
state->nz--;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2014-08-28 12:14:28 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
state->mode = 0; /* zero encoding is next */
|
|
|
|
|
/* unary encoding */
|
|
|
|
|
/* read sign bit */
|
2024-08-23 11:57:26 +02:00
|
|
|
const UINT32 sign = (bs->accumulator & 0x80000000) ? 1 : 0;
|
2014-08-28 12:14:28 -04:00
|
|
|
BitStream_Shift(bs, 1);
|
2014-09-02 18:15:36 -04:00
|
|
|
|
2019-12-10 16:19:20 +01:00
|
|
|
if (state->kp < 6)
|
2014-09-02 18:15:36 -04:00
|
|
|
state->kp = 0;
|
2019-12-10 16:19:20 +01:00
|
|
|
else
|
|
|
|
|
state->kp -= 6;
|
2014-09-02 18:15:36 -04:00
|
|
|
|
2014-09-02 13:31:40 -04:00
|
|
|
if (numBits == 1)
|
|
|
|
|
return sign ? -1 : 1;
|
|
|
|
|
|
2024-08-23 11:57:26 +02:00
|
|
|
UINT32 mag = 1;
|
|
|
|
|
const UINT32 max = (1 << numBits) - 1;
|
2014-08-28 12:14:28 -04:00
|
|
|
|
2014-09-02 13:31:40 -04:00
|
|
|
while (mag < max)
|
2014-08-28 12:14:28 -04:00
|
|
|
{
|
2024-08-23 11:57:26 +02:00
|
|
|
const UINT32 bit = (bs->accumulator & 0x80000000) ? 1 : 0;
|
2014-09-02 13:31:40 -04:00
|
|
|
BitStream_Shift(bs, 1);
|
2014-08-28 12:14:28 -04:00
|
|
|
|
2014-09-02 13:31:40 -04:00
|
|
|
if (bit)
|
|
|
|
|
break;
|
2014-08-28 12:14:28 -04:00
|
|
|
|
2014-09-02 13:31:40 -04:00
|
|
|
mag++;
|
2014-08-28 12:14:28 -04:00
|
|
|
}
|
|
|
|
|
|
2024-09-15 08:43:31 +02:00
|
|
|
if (mag > INT16_MAX)
|
|
|
|
|
mag = INT16_MAX;
|
2024-09-18 11:36:17 +02:00
|
|
|
return (INT16)(sign ? -1 * (int)mag : (INT16)mag);
|
2014-08-28 12:14:28 -04:00
|
|
|
}
|
|
|
|
|
|
2025-09-22 12:19:02 +02:00
|
|
|
static inline int
|
2024-05-29 23:53:33 +02:00
|
|
|
progressive_rfx_upgrade_state_finish(RFX_PROGRESSIVE_UPGRADE_STATE* WINPR_RESTRICT state)
|
2014-09-09 14:36:04 -04:00
|
|
|
{
|
2024-01-23 16:49:54 +01:00
|
|
|
UINT32 pad = 0;
|
2026-02-26 15:06:27 +01:00
|
|
|
wBitStream* srl = nullptr;
|
|
|
|
|
wBitStream* raw = nullptr;
|
2019-12-10 16:19:20 +01:00
|
|
|
if (!state)
|
|
|
|
|
return -1;
|
|
|
|
|
|
2014-09-09 14:36:04 -04:00
|
|
|
srl = state->srl;
|
|
|
|
|
raw = state->raw;
|
|
|
|
|
/* Read trailing bits from RAW/SRL bit streams */
|
|
|
|
|
pad = (raw->position % 8) ? (8 - (raw->position % 8)) : 0;
|
|
|
|
|
|
|
|
|
|
if (pad)
|
|
|
|
|
BitStream_Shift(raw, pad);
|
|
|
|
|
|
|
|
|
|
pad = (srl->position % 8) ? (8 - (srl->position % 8)) : 0;
|
|
|
|
|
|
|
|
|
|
if (pad)
|
|
|
|
|
BitStream_Shift(srl, pad);
|
|
|
|
|
|
|
|
|
|
if (BitStream_GetRemainingLength(srl) == 8)
|
|
|
|
|
BitStream_Shift(srl, 8);
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-14 16:56:10 +01:00
|
|
|
static inline int16_t rawShift(wBitStream* raw, UINT32 numBits)
|
|
|
|
|
{
|
|
|
|
|
WINPR_ASSERT(raw);
|
|
|
|
|
WINPR_ASSERT(numBits > 0);
|
|
|
|
|
|
|
|
|
|
raw->mask = ((1 << numBits) - 1);
|
2026-02-20 16:32:22 +01:00
|
|
|
const int16_t input = (int16_t)((raw->accumulator >> (32 - numBits)) & raw->mask);
|
2026-01-14 16:56:10 +01:00
|
|
|
BitStream_Shift(raw, numBits);
|
2026-02-20 16:32:22 +01:00
|
|
|
return input;
|
2026-01-14 16:56:10 +01:00
|
|
|
}
|
|
|
|
|
|
2025-09-22 12:19:02 +02:00
|
|
|
static inline int progressive_rfx_upgrade_block(RFX_PROGRESSIVE_UPGRADE_STATE* WINPR_RESTRICT state,
|
2024-05-29 23:53:33 +02:00
|
|
|
INT16* WINPR_RESTRICT buffer,
|
|
|
|
|
INT16* WINPR_RESTRICT sign, UINT32 length,
|
2025-02-13 15:29:10 +01:00
|
|
|
UINT32 shift, WINPR_ATTR_UNUSED UINT32 bitPos,
|
|
|
|
|
UINT32 numBits)
|
2014-08-27 18:34:37 -04:00
|
|
|
{
|
2026-01-14 16:56:10 +01:00
|
|
|
if (numBits < 1)
|
2014-08-28 12:14:28 -04:00
|
|
|
return 1;
|
|
|
|
|
|
2025-01-15 14:57:14 +01:00
|
|
|
wBitStream* raw = state->raw;
|
|
|
|
|
int32_t input = 0;
|
2014-08-27 18:34:37 -04:00
|
|
|
|
|
|
|
|
if (!state->nonLL)
|
|
|
|
|
{
|
2024-01-30 10:25:38 +01:00
|
|
|
for (UINT32 index = 0; index < length; index++)
|
2014-08-27 18:34:37 -04:00
|
|
|
{
|
2026-01-14 16:56:10 +01:00
|
|
|
input = rawShift(raw, numBits);
|
2025-01-15 14:57:14 +01:00
|
|
|
|
|
|
|
|
const int32_t shifted = input << shift;
|
|
|
|
|
const int32_t val = buffer[index] + shifted;
|
|
|
|
|
const int16_t ival = WINPR_ASSERTING_INT_CAST(int16_t, val);
|
|
|
|
|
buffer[index] = ival;
|
2014-08-27 18:34:37 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2024-01-30 10:25:38 +01:00
|
|
|
for (UINT32 index = 0; index < length; index++)
|
2014-08-27 18:34:37 -04:00
|
|
|
{
|
2014-08-28 15:14:01 -04:00
|
|
|
if (sign[index] > 0)
|
2014-08-27 18:34:37 -04:00
|
|
|
{
|
|
|
|
|
/* sign > 0, read from raw */
|
2026-01-14 16:56:10 +01:00
|
|
|
input = rawShift(raw, numBits);
|
2014-08-27 18:34:37 -04:00
|
|
|
}
|
2014-08-28 15:14:01 -04:00
|
|
|
else if (sign[index] < 0)
|
2014-08-27 18:34:37 -04:00
|
|
|
{
|
|
|
|
|
/* sign < 0, read from raw */
|
2026-01-14 16:56:10 +01:00
|
|
|
input = rawShift(raw, numBits);
|
2026-02-20 16:32:22 +01:00
|
|
|
input *= -1;
|
2014-08-27 18:34:37 -04:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* sign == 0, read from srl */
|
2014-08-28 12:14:28 -04:00
|
|
|
input = progressive_rfx_srl_read(state, numBits);
|
2025-01-15 14:57:14 +01:00
|
|
|
sign[index] = WINPR_ASSERTING_INT_CAST(int16_t, input);
|
2014-08-27 18:34:37 -04:00
|
|
|
}
|
2014-08-28 15:14:01 -04:00
|
|
|
|
2026-02-20 16:32:22 +01:00
|
|
|
const int32_t val = input << shift;
|
2025-01-15 14:57:14 +01:00
|
|
|
const int32_t ival = buffer[index] + val;
|
|
|
|
|
buffer[index] = WINPR_ASSERTING_INT_CAST(INT16, ival);
|
2014-08-27 18:34:37 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-22 12:19:02 +02:00
|
|
|
static inline int progressive_rfx_upgrade_component(
|
2025-02-13 15:29:10 +01:00
|
|
|
PROGRESSIVE_CONTEXT* WINPR_RESTRICT progressive,
|
|
|
|
|
const RFX_COMPONENT_CODEC_QUANT* WINPR_RESTRICT shift,
|
|
|
|
|
const RFX_COMPONENT_CODEC_QUANT* WINPR_RESTRICT bitPos,
|
|
|
|
|
const RFX_COMPONENT_CODEC_QUANT* WINPR_RESTRICT numBits, INT16* WINPR_RESTRICT buffer,
|
|
|
|
|
INT16* WINPR_RESTRICT current, INT16* WINPR_RESTRICT sign, const BYTE* WINPR_RESTRICT srlData,
|
|
|
|
|
UINT32 srlLen, const BYTE* WINPR_RESTRICT rawData, UINT32 rawLen, BOOL coeffDiff,
|
|
|
|
|
WINPR_ATTR_UNUSED BOOL subbandDiff, BOOL extrapolate)
|
2014-08-27 18:34:37 -04:00
|
|
|
{
|
2024-01-23 16:49:54 +01:00
|
|
|
int rc = 0;
|
|
|
|
|
UINT32 aRawLen = 0;
|
|
|
|
|
UINT32 aSrlLen = 0;
|
2026-02-24 20:18:25 +01:00
|
|
|
wBitStream s_srl = WINPR_C_ARRAY_INIT;
|
|
|
|
|
wBitStream s_raw = WINPR_C_ARRAY_INIT;
|
|
|
|
|
RFX_PROGRESSIVE_UPGRADE_STATE state = WINPR_C_ARRAY_INIT;
|
2017-05-02 18:39:03 +02:00
|
|
|
|
2014-08-28 12:14:28 -04:00
|
|
|
state.kp = 8;
|
2014-09-02 18:15:36 -04:00
|
|
|
state.mode = 0;
|
2014-08-27 18:34:37 -04:00
|
|
|
state.srl = &s_srl;
|
|
|
|
|
state.raw = &s_raw;
|
|
|
|
|
BitStream_Attach(state.srl, srlData, srlLen);
|
|
|
|
|
BitStream_Fetch(state.srl);
|
|
|
|
|
BitStream_Attach(state.raw, rawData, rawLen);
|
|
|
|
|
BitStream_Fetch(state.raw);
|
2017-05-02 18:39:03 +02:00
|
|
|
|
2014-08-27 18:34:37 -04:00
|
|
|
state.nonLL = TRUE;
|
2019-12-10 16:19:20 +01:00
|
|
|
rc = progressive_rfx_upgrade_block(&state, ¤t[0], &sign[0], 1023, shift->HL1, bitPos->HL1,
|
|
|
|
|
numBits->HL1); /* HL1 */
|
|
|
|
|
if (rc < 0)
|
|
|
|
|
return rc;
|
|
|
|
|
rc = progressive_rfx_upgrade_block(&state, ¤t[1023], &sign[1023], 1023, shift->LH1,
|
|
|
|
|
bitPos->LH1, numBits->LH1); /* LH1 */
|
|
|
|
|
if (rc < 0)
|
|
|
|
|
return rc;
|
|
|
|
|
rc = progressive_rfx_upgrade_block(&state, ¤t[2046], &sign[2046], 961, shift->HH1,
|
|
|
|
|
bitPos->HH1, numBits->HH1); /* HH1 */
|
|
|
|
|
if (rc < 0)
|
|
|
|
|
return rc;
|
|
|
|
|
rc = progressive_rfx_upgrade_block(&state, ¤t[3007], &sign[3007], 272, shift->HL2,
|
|
|
|
|
bitPos->HL2, numBits->HL2); /* HL2 */
|
|
|
|
|
if (rc < 0)
|
|
|
|
|
return rc;
|
|
|
|
|
rc = progressive_rfx_upgrade_block(&state, ¤t[3279], &sign[3279], 272, shift->LH2,
|
|
|
|
|
bitPos->LH2, numBits->LH2); /* LH2 */
|
|
|
|
|
if (rc < 0)
|
|
|
|
|
return rc;
|
|
|
|
|
rc = progressive_rfx_upgrade_block(&state, ¤t[3551], &sign[3551], 256, shift->HH2,
|
|
|
|
|
bitPos->HH2, numBits->HH2); /* HH2 */
|
|
|
|
|
if (rc < 0)
|
|
|
|
|
return rc;
|
|
|
|
|
rc = progressive_rfx_upgrade_block(&state, ¤t[3807], &sign[3807], 72, shift->HL3,
|
|
|
|
|
bitPos->HL3, numBits->HL3); /* HL3 */
|
|
|
|
|
if (rc < 0)
|
|
|
|
|
return rc;
|
|
|
|
|
rc = progressive_rfx_upgrade_block(&state, ¤t[3879], &sign[3879], 72, shift->LH3,
|
|
|
|
|
bitPos->LH3, numBits->LH3); /* LH3 */
|
|
|
|
|
if (rc < 0)
|
|
|
|
|
return rc;
|
|
|
|
|
rc = progressive_rfx_upgrade_block(&state, ¤t[3951], &sign[3951], 64, shift->HH3,
|
|
|
|
|
bitPos->HH3, numBits->HH3); /* HH3 */
|
|
|
|
|
if (rc < 0)
|
|
|
|
|
return rc;
|
2017-05-02 18:39:03 +02:00
|
|
|
|
2014-08-27 18:34:37 -04:00
|
|
|
state.nonLL = FALSE;
|
2019-12-10 16:19:20 +01:00
|
|
|
rc = progressive_rfx_upgrade_block(&state, ¤t[4015], &sign[4015], 81, shift->LL3,
|
|
|
|
|
bitPos->LL3, numBits->LL3); /* LL3 */
|
|
|
|
|
if (rc < 0)
|
|
|
|
|
return rc;
|
|
|
|
|
rc = progressive_rfx_upgrade_state_finish(&state);
|
|
|
|
|
if (rc < 0)
|
|
|
|
|
return rc;
|
2014-08-28 12:14:28 -04:00
|
|
|
aRawLen = (state.raw->position + 7) / 8;
|
|
|
|
|
aSrlLen = (state.srl->position + 7) / 8;
|
2014-08-27 17:02:15 -04:00
|
|
|
|
2014-08-28 12:14:28 -04:00
|
|
|
if ((aRawLen != rawLen) || (aSrlLen != srlLen))
|
2014-08-01 09:44:00 -04:00
|
|
|
{
|
2014-08-28 12:14:28 -04:00
|
|
|
int pRawLen = 0;
|
|
|
|
|
int pSrlLen = 0;
|
2014-08-01 09:44:00 -04:00
|
|
|
|
2014-08-28 12:14:28 -04:00
|
|
|
if (rawLen)
|
2019-11-06 15:24:51 +01:00
|
|
|
pRawLen = (int)((((float)aRawLen) / ((float)rawLen)) * 100.0f);
|
2014-07-31 15:08:54 -04:00
|
|
|
|
2014-08-28 12:14:28 -04:00
|
|
|
if (srlLen)
|
2019-11-06 15:24:51 +01:00
|
|
|
pSrlLen = (int)((((float)aSrlLen) / ((float)srlLen)) * 100.0f);
|
2014-08-26 14:36:33 -04:00
|
|
|
|
2022-12-13 11:18:11 +01:00
|
|
|
WLog_Print(progressive->log, WLOG_WARN,
|
2019-11-06 15:24:51 +01:00
|
|
|
"RAW: %" PRIu32 "/%" PRIu32 " %d%% (%" PRIu32 "/%" PRIu32 ":%" PRIu32
|
|
|
|
|
")\tSRL: %" PRIu32 "/%" PRIu32 " %d%% (%" PRIu32 "/%" PRIu32 ":%" PRIu32 ")",
|
2017-01-18 15:25:24 +01:00
|
|
|
aRawLen, rawLen, pRawLen, state.raw->position, rawLen * 8,
|
2019-11-06 15:24:51 +01:00
|
|
|
(rawLen * 8) - state.raw->position, aSrlLen, srlLen, pSrlLen,
|
|
|
|
|
state.srl->position, srlLen * 8, (srlLen * 8) - state.srl->position);
|
2014-08-28 15:14:01 -04:00
|
|
|
return -1;
|
2014-08-26 14:36:33 -04:00
|
|
|
}
|
|
|
|
|
|
2019-12-16 08:34:42 +01:00
|
|
|
return progressive_rfx_dwt_2d_decode(progressive, buffer, current, coeffDiff, extrapolate,
|
|
|
|
|
TRUE);
|
2014-07-31 15:08:54 -04:00
|
|
|
}
|
|
|
|
|
|
2025-09-22 12:19:02 +02:00
|
|
|
static inline int
|
2024-05-29 23:53:33 +02:00
|
|
|
progressive_decompress_tile_upgrade(PROGRESSIVE_CONTEXT* WINPR_RESTRICT progressive,
|
|
|
|
|
RFX_PROGRESSIVE_TILE* WINPR_RESTRICT tile,
|
|
|
|
|
PROGRESSIVE_BLOCK_REGION* WINPR_RESTRICT region,
|
|
|
|
|
const PROGRESSIVE_BLOCK_CONTEXT* WINPR_RESTRICT context)
|
2014-07-31 15:08:54 -04:00
|
|
|
{
|
2024-01-23 16:49:54 +01:00
|
|
|
int status = 0;
|
|
|
|
|
BOOL coeffDiff = 0;
|
|
|
|
|
BOOL sub = 0;
|
|
|
|
|
BOOL extrapolate = 0;
|
2026-02-26 15:06:27 +01:00
|
|
|
BYTE* pBuffer = nullptr;
|
2026-02-24 20:18:25 +01:00
|
|
|
INT16* pSign[3] = WINPR_C_ARRAY_INIT;
|
|
|
|
|
INT16* pSrcDst[3] = WINPR_C_ARRAY_INIT;
|
|
|
|
|
INT16* pCurrent[3] = WINPR_C_ARRAY_INIT;
|
|
|
|
|
RFX_COMPONENT_CODEC_QUANT shiftY = WINPR_C_ARRAY_INIT;
|
|
|
|
|
RFX_COMPONENT_CODEC_QUANT shiftCb = WINPR_C_ARRAY_INIT;
|
|
|
|
|
RFX_COMPONENT_CODEC_QUANT shiftCr = WINPR_C_ARRAY_INIT;
|
|
|
|
|
RFX_COMPONENT_CODEC_QUANT yBitPos = WINPR_C_ARRAY_INIT;
|
|
|
|
|
RFX_COMPONENT_CODEC_QUANT cbBitPos = WINPR_C_ARRAY_INIT;
|
|
|
|
|
RFX_COMPONENT_CODEC_QUANT crBitPos = WINPR_C_ARRAY_INIT;
|
|
|
|
|
RFX_COMPONENT_CODEC_QUANT yNumBits = WINPR_C_ARRAY_INIT;
|
|
|
|
|
RFX_COMPONENT_CODEC_QUANT cbNumBits = WINPR_C_ARRAY_INIT;
|
|
|
|
|
RFX_COMPONENT_CODEC_QUANT crNumBits = WINPR_C_ARRAY_INIT;
|
2026-02-26 15:06:27 +01:00
|
|
|
RFX_COMPONENT_CODEC_QUANT* quantY = nullptr;
|
|
|
|
|
RFX_COMPONENT_CODEC_QUANT* quantCb = nullptr;
|
|
|
|
|
RFX_COMPONENT_CODEC_QUANT* quantCr = nullptr;
|
|
|
|
|
RFX_COMPONENT_CODEC_QUANT* quantProgY = nullptr;
|
|
|
|
|
RFX_COMPONENT_CODEC_QUANT* quantProgCb = nullptr;
|
|
|
|
|
RFX_COMPONENT_CODEC_QUANT* quantProgCr = nullptr;
|
|
|
|
|
RFX_PROGRESSIVE_CODEC_QUANT* quantProg = nullptr;
|
2014-08-28 15:14:01 -04:00
|
|
|
static const prim_size_t roi_64x64 = { 64, 64 };
|
|
|
|
|
const primitives_t* prims = primitives_get();
|
2019-12-10 16:19:20 +01:00
|
|
|
|
2019-12-16 08:34:42 +01:00
|
|
|
coeffDiff = tile->flags & RFX_TILE_DIFFERENCE;
|
2019-12-10 16:19:20 +01:00
|
|
|
sub = context->flags & RFX_SUBBAND_DIFFING;
|
|
|
|
|
extrapolate = region->flags & RFX_DWT_REDUCE_EXTRAPOLATE;
|
|
|
|
|
|
2014-08-28 12:14:28 -04:00
|
|
|
tile->pass++;
|
2022-12-13 11:18:11 +01:00
|
|
|
|
|
|
|
|
#if defined(WITH_DEBUG_CODECS)
|
2017-01-18 15:25:24 +01:00
|
|
|
WLog_Print(progressive->log, WLOG_DEBUG,
|
2019-11-06 15:24:51 +01:00
|
|
|
"ProgressiveTileUpgrade: pass: %" PRIu16 " quantIdx Y: %" PRIu8 " Cb: %" PRIu8
|
|
|
|
|
" Cr: %" PRIu8 " xIdx: %" PRIu16 " yIdx: %" PRIu16 " quality: %" PRIu8
|
|
|
|
|
" ySrlLen: %" PRIu16 " yRawLen: %" PRIu16 " cbSrlLen: %" PRIu16 " cbRawLen: %" PRIu16
|
|
|
|
|
" crSrlLen: %" PRIu16 " crRawLen: %" PRIu16 "",
|
2017-01-18 15:25:24 +01:00
|
|
|
tile->pass, tile->quantIdxY, tile->quantIdxCb, tile->quantIdxCr, tile->xIdx,
|
|
|
|
|
tile->yIdx, tile->quality, tile->ySrlLen, tile->yRawLen, tile->cbSrlLen,
|
|
|
|
|
tile->cbRawLen, tile->crSrlLen, tile->crRawLen);
|
2022-12-13 11:18:11 +01:00
|
|
|
#endif
|
2014-07-31 15:08:54 -04:00
|
|
|
|
|
|
|
|
if (tile->quantIdxY >= region->numQuant)
|
2019-12-10 16:19:20 +01:00
|
|
|
{
|
|
|
|
|
WLog_ERR(TAG, "quantIdxY %" PRIu8 " > numQuant %" PRIu8, tile->quantIdxY, region->numQuant);
|
2014-07-31 15:08:54 -04:00
|
|
|
return -1;
|
2019-12-10 16:19:20 +01:00
|
|
|
}
|
2014-07-31 15:08:54 -04:00
|
|
|
|
|
|
|
|
quantY = &(region->quantVals[tile->quantIdxY]);
|
|
|
|
|
|
|
|
|
|
if (tile->quantIdxCb >= region->numQuant)
|
2019-12-10 16:19:20 +01:00
|
|
|
{
|
|
|
|
|
WLog_ERR(TAG, "quantIdxCb %" PRIu8 " > numQuant %" PRIu8, tile->quantIdxCb,
|
|
|
|
|
region->numQuant);
|
2014-07-31 15:08:54 -04:00
|
|
|
return -1;
|
2019-12-10 16:19:20 +01:00
|
|
|
}
|
2014-07-31 15:08:54 -04:00
|
|
|
|
|
|
|
|
quantCb = &(region->quantVals[tile->quantIdxCb]);
|
|
|
|
|
|
|
|
|
|
if (tile->quantIdxCr >= region->numQuant)
|
2019-12-10 16:19:20 +01:00
|
|
|
{
|
|
|
|
|
WLog_ERR(TAG, "quantIdxCr %" PRIu8 " > numQuant %" PRIu8, tile->quantIdxCr,
|
|
|
|
|
region->numQuant);
|
2014-07-31 15:08:54 -04:00
|
|
|
return -1;
|
2019-12-10 16:19:20 +01:00
|
|
|
}
|
2014-07-31 15:08:54 -04:00
|
|
|
|
|
|
|
|
quantCr = &(region->quantVals[tile->quantIdxCr]);
|
|
|
|
|
|
|
|
|
|
if (tile->quality == 0xFF)
|
|
|
|
|
{
|
2014-08-27 17:02:15 -04:00
|
|
|
quantProg = &(progressive->quantProgValFull);
|
2014-07-31 15:08:54 -04:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (tile->quality >= region->numProgQuant)
|
2019-12-10 16:19:20 +01:00
|
|
|
{
|
|
|
|
|
WLog_ERR(TAG, "quality %" PRIu8 " > numProgQuant %" PRIu8, tile->quality,
|
|
|
|
|
region->numProgQuant);
|
2014-07-31 15:08:54 -04:00
|
|
|
return -1;
|
2019-12-10 16:19:20 +01:00
|
|
|
}
|
2014-07-31 15:08:54 -04:00
|
|
|
|
2014-08-27 17:02:15 -04:00
|
|
|
quantProg = &(region->quantProgVals[tile->quality]);
|
2014-07-31 15:08:54 -04:00
|
|
|
}
|
|
|
|
|
|
2014-08-27 17:02:15 -04:00
|
|
|
quantProgY = &(quantProg->yQuantValues);
|
|
|
|
|
quantProgCb = &(quantProg->cbQuantValues);
|
|
|
|
|
quantProgCr = &(quantProg->crQuantValues);
|
|
|
|
|
|
2014-09-02 13:31:40 -04:00
|
|
|
if (!progressive_rfx_quant_cmp_equal(quantY, &(tile->yQuant)))
|
2017-01-18 15:25:24 +01:00
|
|
|
WLog_Print(progressive->log, WLOG_WARN, "non-progressive quantY has changed!");
|
2016-04-11 14:14:17 +02:00
|
|
|
|
2014-09-02 13:31:40 -04:00
|
|
|
if (!progressive_rfx_quant_cmp_equal(quantCb, &(tile->cbQuant)))
|
2017-01-18 15:25:24 +01:00
|
|
|
WLog_Print(progressive->log, WLOG_WARN, "non-progressive quantCb has changed!");
|
2016-04-11 14:14:17 +02:00
|
|
|
|
2014-09-02 13:31:40 -04:00
|
|
|
if (!progressive_rfx_quant_cmp_equal(quantCr, &(tile->crQuant)))
|
2017-01-18 15:25:24 +01:00
|
|
|
WLog_Print(progressive->log, WLOG_WARN, "non-progressive quantCr has changed!");
|
2014-09-02 13:31:40 -04:00
|
|
|
|
2019-12-10 16:19:20 +01:00
|
|
|
if (!(context->flags & RFX_SUBBAND_DIFFING))
|
|
|
|
|
WLog_WARN(TAG, "PROGRESSIVE_BLOCK_CONTEXT::flags & RFX_SUBBAND_DIFFING not set");
|
|
|
|
|
|
2014-09-02 13:31:40 -04:00
|
|
|
progressive_rfx_quant_add(quantY, quantProgY, &yBitPos);
|
|
|
|
|
progressive_rfx_quant_add(quantCb, quantProgCb, &cbBitPos);
|
|
|
|
|
progressive_rfx_quant_add(quantCr, quantProgCr, &crBitPos);
|
|
|
|
|
progressive_rfx_quant_sub(&(tile->yBitPos), &yBitPos, &yNumBits);
|
|
|
|
|
progressive_rfx_quant_sub(&(tile->cbBitPos), &cbBitPos, &cbNumBits);
|
|
|
|
|
progressive_rfx_quant_sub(&(tile->crBitPos), &crBitPos, &crNumBits);
|
2014-09-02 19:25:01 -04:00
|
|
|
progressive_rfx_quant_add(quantY, quantProgY, &shiftY);
|
|
|
|
|
progressive_rfx_quant_lsub(&shiftY, 1); /* -6 + 5 = -1 */
|
|
|
|
|
progressive_rfx_quant_add(quantCb, quantProgCb, &shiftCb);
|
|
|
|
|
progressive_rfx_quant_lsub(&shiftCb, 1); /* -6 + 5 = -1 */
|
|
|
|
|
progressive_rfx_quant_add(quantCr, quantProgCr, &shiftCr);
|
|
|
|
|
progressive_rfx_quant_lsub(&shiftCr, 1); /* -6 + 5 = -1 */
|
2017-05-02 18:39:03 +02:00
|
|
|
|
2019-12-10 16:19:20 +01:00
|
|
|
tile->yBitPos = yBitPos;
|
|
|
|
|
tile->cbBitPos = cbBitPos;
|
|
|
|
|
tile->crBitPos = crBitPos;
|
|
|
|
|
tile->yQuant = *quantY;
|
|
|
|
|
tile->cbQuant = *quantCb;
|
|
|
|
|
tile->crQuant = *quantCr;
|
|
|
|
|
tile->yProgQuant = *quantProgY;
|
|
|
|
|
tile->cbProgQuant = *quantProgCb;
|
|
|
|
|
tile->crProgQuant = *quantProgCr;
|
|
|
|
|
|
2024-08-29 11:11:11 +02:00
|
|
|
pSign[0] = (INT16*)((&tile->sign[((8192 + 32) * 0) + 16])); /* Y/R buffer */
|
|
|
|
|
pSign[1] = (INT16*)((&tile->sign[((8192 + 32) * 1) + 16])); /* Cb/G buffer */
|
|
|
|
|
pSign[2] = (INT16*)((&tile->sign[((8192 + 32) * 2) + 16])); /* Cr/B buffer */
|
2019-12-10 16:19:20 +01:00
|
|
|
|
2024-08-29 11:11:11 +02:00
|
|
|
pCurrent[0] = (INT16*)((&tile->current[((8192 + 32) * 0) + 16])); /* Y/R buffer */
|
|
|
|
|
pCurrent[1] = (INT16*)((&tile->current[((8192 + 32) * 1) + 16])); /* Cb/G buffer */
|
|
|
|
|
pCurrent[2] = (INT16*)((&tile->current[((8192 + 32) * 2) + 16])); /* Cr/B buffer */
|
2017-05-02 18:39:03 +02:00
|
|
|
|
2019-11-06 15:24:51 +01:00
|
|
|
pBuffer = (BYTE*)BufferPool_Take(progressive->bufferPool, -1);
|
2024-08-29 11:11:11 +02:00
|
|
|
pSrcDst[0] = (INT16*)((&pBuffer[((8192 + 32) * 0) + 16])); /* Y/R buffer */
|
|
|
|
|
pSrcDst[1] = (INT16*)((&pBuffer[((8192 + 32) * 1) + 16])); /* Cb/G buffer */
|
|
|
|
|
pSrcDst[2] = (INT16*)((&pBuffer[((8192 + 32) * 2) + 16])); /* Cr/B buffer */
|
2017-05-02 18:39:03 +02:00
|
|
|
|
2019-12-16 08:34:42 +01:00
|
|
|
status = progressive_rfx_upgrade_component(progressive, &shiftY, quantProgY, &yNumBits,
|
|
|
|
|
pSrcDst[0], pCurrent[0], pSign[0], tile->ySrlData,
|
|
|
|
|
tile->ySrlLen, tile->yRawData, tile->yRawLen,
|
|
|
|
|
coeffDiff, sub, extrapolate); /* Y */
|
2014-08-28 15:14:01 -04:00
|
|
|
|
|
|
|
|
if (status < 0)
|
2019-12-10 16:19:20 +01:00
|
|
|
goto fail;
|
2014-08-28 15:14:01 -04:00
|
|
|
|
2019-12-10 16:19:20 +01:00
|
|
|
status = progressive_rfx_upgrade_component(progressive, &shiftCb, quantProgCb, &cbNumBits,
|
|
|
|
|
pSrcDst[1], pCurrent[1], pSign[1], tile->cbSrlData,
|
2019-12-16 08:34:42 +01:00
|
|
|
tile->cbSrlLen, tile->cbRawData, tile->cbRawLen,
|
|
|
|
|
coeffDiff, sub, extrapolate); /* Cb */
|
2014-08-28 15:14:01 -04:00
|
|
|
|
|
|
|
|
if (status < 0)
|
2019-12-10 16:19:20 +01:00
|
|
|
goto fail;
|
2014-08-28 15:14:01 -04:00
|
|
|
|
2019-12-10 16:19:20 +01:00
|
|
|
status = progressive_rfx_upgrade_component(progressive, &shiftCr, quantProgCr, &crNumBits,
|
|
|
|
|
pSrcDst[2], pCurrent[2], pSign[2], tile->crSrlData,
|
2019-12-16 08:34:42 +01:00
|
|
|
tile->crSrlLen, tile->crRawData, tile->crRawLen,
|
|
|
|
|
coeffDiff, sub, extrapolate); /* Cr */
|
2014-08-28 15:14:01 -04:00
|
|
|
|
|
|
|
|
if (status < 0)
|
2019-12-10 16:19:20 +01:00
|
|
|
goto fail;
|
2014-08-28 15:14:01 -04:00
|
|
|
|
2026-01-08 10:32:29 +01:00
|
|
|
{
|
|
|
|
|
const INT16** ptr = WINPR_REINTERPRET_CAST(pSrcDst, INT16**, const INT16**);
|
|
|
|
|
status = prims->yCbCrToRGB_16s8u_P3AC4R(ptr, 64 * 2, tile->data, tile->stride,
|
|
|
|
|
progressive->format, &roi_64x64);
|
|
|
|
|
}
|
2019-12-10 16:19:20 +01:00
|
|
|
fail:
|
2014-08-28 15:14:01 -04:00
|
|
|
BufferPool_Return(progressive->bufferPool, pBuffer);
|
2019-12-10 16:19:20 +01:00
|
|
|
return status;
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-22 12:19:02 +02:00
|
|
|
static inline BOOL progressive_tile_read_upgrade(
|
2024-05-29 23:53:33 +02:00
|
|
|
PROGRESSIVE_CONTEXT* WINPR_RESTRICT progressive, wStream* WINPR_RESTRICT s, UINT16 blockType,
|
|
|
|
|
UINT32 blockLen, PROGRESSIVE_SURFACE_CONTEXT* WINPR_RESTRICT surface,
|
|
|
|
|
PROGRESSIVE_BLOCK_REGION* WINPR_RESTRICT region,
|
2025-02-13 15:29:10 +01:00
|
|
|
WINPR_ATTR_UNUSED const PROGRESSIVE_BLOCK_CONTEXT* WINPR_RESTRICT context)
|
2019-12-10 16:19:20 +01:00
|
|
|
{
|
2026-02-24 20:18:25 +01:00
|
|
|
RFX_PROGRESSIVE_TILE tile = WINPR_C_ARRAY_INIT;
|
2019-12-10 16:19:20 +01:00
|
|
|
const size_t expect = 20;
|
|
|
|
|
|
2022-04-19 14:29:17 +02:00
|
|
|
if (!Stream_CheckAndLogRequiredLength(TAG, s, expect))
|
2019-12-10 16:19:20 +01:00
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
tile.blockType = blockType;
|
|
|
|
|
tile.blockLen = blockLen;
|
|
|
|
|
tile.flags = 0;
|
|
|
|
|
|
|
|
|
|
Stream_Read_UINT8(s, tile.quantIdxY);
|
|
|
|
|
Stream_Read_UINT8(s, tile.quantIdxCb);
|
|
|
|
|
Stream_Read_UINT8(s, tile.quantIdxCr);
|
|
|
|
|
Stream_Read_UINT16(s, tile.xIdx);
|
|
|
|
|
Stream_Read_UINT16(s, tile.yIdx);
|
|
|
|
|
Stream_Read_UINT8(s, tile.quality);
|
|
|
|
|
Stream_Read_UINT16(s, tile.ySrlLen);
|
|
|
|
|
Stream_Read_UINT16(s, tile.yRawLen);
|
|
|
|
|
Stream_Read_UINT16(s, tile.cbSrlLen);
|
|
|
|
|
Stream_Read_UINT16(s, tile.cbRawLen);
|
|
|
|
|
Stream_Read_UINT16(s, tile.crSrlLen);
|
|
|
|
|
Stream_Read_UINT16(s, tile.crRawLen);
|
|
|
|
|
|
|
|
|
|
tile.ySrlData = Stream_Pointer(s);
|
|
|
|
|
if (!Stream_SafeSeek(s, tile.ySrlLen))
|
|
|
|
|
{
|
|
|
|
|
WLog_Print(progressive->log, WLOG_ERROR, " Failed to seek %" PRIu32 " bytes", tile.ySrlLen);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tile.yRawData = Stream_Pointer(s);
|
|
|
|
|
if (!Stream_SafeSeek(s, tile.yRawLen))
|
|
|
|
|
{
|
|
|
|
|
WLog_Print(progressive->log, WLOG_ERROR, " Failed to seek %" PRIu32 " bytes", tile.yRawLen);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tile.cbSrlData = Stream_Pointer(s);
|
|
|
|
|
if (!Stream_SafeSeek(s, tile.cbSrlLen))
|
|
|
|
|
{
|
|
|
|
|
WLog_Print(progressive->log, WLOG_ERROR, " Failed to seek %" PRIu32 " bytes",
|
|
|
|
|
tile.cbSrlLen);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tile.cbRawData = Stream_Pointer(s);
|
|
|
|
|
if (!Stream_SafeSeek(s, tile.cbRawLen))
|
|
|
|
|
{
|
|
|
|
|
WLog_Print(progressive->log, WLOG_ERROR, " Failed to seek %" PRIu32 " bytes",
|
|
|
|
|
tile.cbRawLen);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tile.crSrlData = Stream_Pointer(s);
|
|
|
|
|
if (!Stream_SafeSeek(s, tile.crSrlLen))
|
|
|
|
|
{
|
|
|
|
|
WLog_Print(progressive->log, WLOG_ERROR, " Failed to seek %" PRIu32 " bytes",
|
|
|
|
|
tile.crSrlLen);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tile.crRawData = Stream_Pointer(s);
|
|
|
|
|
if (!Stream_SafeSeek(s, tile.crRawLen))
|
|
|
|
|
{
|
|
|
|
|
WLog_Print(progressive->log, WLOG_ERROR, " Failed to seek %" PRIu32 " bytes",
|
|
|
|
|
tile.crRawLen);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return progressive_surface_tile_replace(surface, region, &tile, TRUE);
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-22 12:19:02 +02:00
|
|
|
static inline BOOL
|
|
|
|
|
progressive_tile_read(PROGRESSIVE_CONTEXT* WINPR_RESTRICT progressive, BOOL simple,
|
|
|
|
|
wStream* WINPR_RESTRICT s, UINT16 blockType, UINT32 blockLen,
|
|
|
|
|
PROGRESSIVE_SURFACE_CONTEXT* WINPR_RESTRICT surface,
|
|
|
|
|
PROGRESSIVE_BLOCK_REGION* WINPR_RESTRICT region,
|
|
|
|
|
WINPR_ATTR_UNUSED const PROGRESSIVE_BLOCK_CONTEXT* WINPR_RESTRICT context)
|
2019-12-10 16:19:20 +01:00
|
|
|
{
|
2026-02-24 20:18:25 +01:00
|
|
|
RFX_PROGRESSIVE_TILE tile = WINPR_C_ARRAY_INIT;
|
2019-12-10 16:19:20 +01:00
|
|
|
size_t expect = simple ? 16 : 17;
|
|
|
|
|
|
2022-04-19 14:29:17 +02:00
|
|
|
if (!Stream_CheckAndLogRequiredLength(TAG, s, expect))
|
2019-12-10 16:19:20 +01:00
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
tile.blockType = blockType;
|
|
|
|
|
tile.blockLen = blockLen;
|
|
|
|
|
|
|
|
|
|
Stream_Read_UINT8(s, tile.quantIdxY);
|
|
|
|
|
Stream_Read_UINT8(s, tile.quantIdxCb);
|
|
|
|
|
Stream_Read_UINT8(s, tile.quantIdxCr);
|
|
|
|
|
Stream_Read_UINT16(s, tile.xIdx);
|
|
|
|
|
Stream_Read_UINT16(s, tile.yIdx);
|
|
|
|
|
Stream_Read_UINT8(s, tile.flags);
|
|
|
|
|
|
|
|
|
|
if (!simple)
|
|
|
|
|
Stream_Read_UINT8(s, tile.quality);
|
|
|
|
|
else
|
|
|
|
|
tile.quality = 0xFF;
|
|
|
|
|
Stream_Read_UINT16(s, tile.yLen);
|
|
|
|
|
Stream_Read_UINT16(s, tile.cbLen);
|
|
|
|
|
Stream_Read_UINT16(s, tile.crLen);
|
|
|
|
|
Stream_Read_UINT16(s, tile.tailLen);
|
|
|
|
|
|
|
|
|
|
tile.yData = Stream_Pointer(s);
|
|
|
|
|
if (!Stream_SafeSeek(s, tile.yLen))
|
|
|
|
|
{
|
|
|
|
|
WLog_Print(progressive->log, WLOG_ERROR, " Failed to seek %" PRIu32 " bytes", tile.yLen);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tile.cbData = Stream_Pointer(s);
|
|
|
|
|
if (!Stream_SafeSeek(s, tile.cbLen))
|
|
|
|
|
{
|
|
|
|
|
WLog_Print(progressive->log, WLOG_ERROR, " Failed to seek %" PRIu32 " bytes", tile.cbLen);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tile.crData = Stream_Pointer(s);
|
|
|
|
|
if (!Stream_SafeSeek(s, tile.crLen))
|
|
|
|
|
{
|
|
|
|
|
WLog_Print(progressive->log, WLOG_ERROR, " Failed to seek %" PRIu32 " bytes", tile.crLen);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tile.tailData = Stream_Pointer(s);
|
|
|
|
|
if (!Stream_SafeSeek(s, tile.tailLen))
|
|
|
|
|
{
|
|
|
|
|
WLog_Print(progressive->log, WLOG_ERROR, " Failed to seek %" PRIu32 " bytes", tile.tailLen);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return progressive_surface_tile_replace(surface, region, &tile, FALSE);
|
2014-07-31 15:08:54 -04:00
|
|
|
}
|
|
|
|
|
|
2021-05-24 11:28:02 +02:00
|
|
|
static void CALLBACK progressive_process_tiles_tile_work_callback(PTP_CALLBACK_INSTANCE instance,
|
|
|
|
|
void* context, PTP_WORK work)
|
|
|
|
|
{
|
|
|
|
|
PROGRESSIVE_TILE_PROCESS_WORK_PARAM* param = (PROGRESSIVE_TILE_PROCESS_WORK_PARAM*)context;
|
|
|
|
|
|
2022-04-06 10:10:07 +02:00
|
|
|
WINPR_UNUSED(instance);
|
|
|
|
|
WINPR_UNUSED(work);
|
|
|
|
|
|
2021-05-24 11:28:02 +02:00
|
|
|
switch (param->tile->blockType)
|
|
|
|
|
{
|
|
|
|
|
case PROGRESSIVE_WBT_TILE_SIMPLE:
|
|
|
|
|
case PROGRESSIVE_WBT_TILE_FIRST:
|
|
|
|
|
progressive_decompress_tile_first(param->progressive, param->tile, param->region,
|
|
|
|
|
param->context);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case PROGRESSIVE_WBT_TILE_UPGRADE:
|
|
|
|
|
progressive_decompress_tile_upgrade(param->progressive, param->tile, param->region,
|
|
|
|
|
param->context);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
2022-11-14 09:13:15 +01:00
|
|
|
WLog_Print(param->progressive->log, WLOG_ERROR, "Invalid block type %04" PRIx16 " (%s)",
|
2021-05-24 11:28:02 +02:00
|
|
|
param->tile->blockType,
|
2023-10-06 13:22:17 +02:00
|
|
|
rfx_get_progressive_block_type_string(param->tile->blockType));
|
2021-05-24 11:28:02 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-22 12:19:02 +02:00
|
|
|
static inline SSIZE_T
|
|
|
|
|
progressive_process_tiles(PROGRESSIVE_CONTEXT* WINPR_RESTRICT progressive,
|
|
|
|
|
wStream* WINPR_RESTRICT s,
|
|
|
|
|
PROGRESSIVE_BLOCK_REGION* WINPR_RESTRICT region,
|
|
|
|
|
PROGRESSIVE_SURFACE_CONTEXT* WINPR_RESTRICT surface,
|
|
|
|
|
const PROGRESSIVE_BLOCK_CONTEXT* WINPR_RESTRICT context)
|
2014-07-31 15:08:54 -04:00
|
|
|
{
|
2021-05-24 11:28:02 +02:00
|
|
|
int status = 0;
|
2024-01-23 16:49:54 +01:00
|
|
|
size_t end = 0;
|
2019-12-10 16:19:20 +01:00
|
|
|
const size_t start = Stream_GetPosition(s);
|
2024-01-23 16:49:54 +01:00
|
|
|
UINT16 blockType = 0;
|
|
|
|
|
UINT32 blockLen = 0;
|
2014-08-01 09:44:00 -04:00
|
|
|
UINT32 count = 0;
|
2021-05-24 11:28:02 +02:00
|
|
|
UINT16 close_cnt = 0;
|
2014-07-31 15:08:54 -04:00
|
|
|
|
2022-04-28 08:00:39 +02:00
|
|
|
WINPR_ASSERT(progressive);
|
|
|
|
|
WINPR_ASSERT(region);
|
|
|
|
|
|
2022-04-19 14:29:17 +02:00
|
|
|
if (!Stream_CheckAndLogRequiredLength(TAG, s, region->tileDataSize))
|
2019-12-10 16:19:20 +01:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
while ((Stream_GetRemainingLength(s) >= 6) &&
|
|
|
|
|
(region->tileDataSize > (Stream_GetPosition(s) - start)))
|
|
|
|
|
{
|
|
|
|
|
const size_t pos = Stream_GetPosition(s);
|
|
|
|
|
|
|
|
|
|
Stream_Read_UINT16(s, blockType);
|
|
|
|
|
Stream_Read_UINT32(s, blockLen);
|
|
|
|
|
|
2022-12-13 11:18:11 +01:00
|
|
|
#if defined(WITH_DEBUG_CODECS)
|
2019-11-06 15:24:51 +01:00
|
|
|
WLog_Print(progressive->log, WLOG_DEBUG, "%s",
|
2023-10-06 13:22:17 +02:00
|
|
|
rfx_get_progressive_block_type_string(blockType));
|
2022-12-13 11:18:11 +01:00
|
|
|
#endif
|
2014-07-31 15:08:54 -04:00
|
|
|
|
2022-04-19 14:29:17 +02:00
|
|
|
if (blockLen < 6)
|
2019-12-10 16:19:20 +01:00
|
|
|
{
|
2025-08-13 09:00:25 +02:00
|
|
|
WLog_Print(progressive->log, WLOG_ERROR, "Expected >= %" PRIu32 " remaining %" PRIu32,
|
|
|
|
|
6u, blockLen);
|
2014-08-01 09:44:00 -04:00
|
|
|
return -1003;
|
2019-12-10 16:19:20 +01:00
|
|
|
}
|
2022-04-19 14:29:17 +02:00
|
|
|
if (!Stream_CheckAndLogRequiredLength(TAG, s, blockLen - 6))
|
|
|
|
|
return -1003;
|
2014-07-31 15:08:54 -04:00
|
|
|
|
2014-08-26 16:15:22 -04:00
|
|
|
switch (blockType)
|
2014-08-01 09:44:00 -04:00
|
|
|
{
|
|
|
|
|
case PROGRESSIVE_WBT_TILE_SIMPLE:
|
2019-12-10 16:19:20 +01:00
|
|
|
if (!progressive_tile_read(progressive, TRUE, s, blockType, blockLen, surface,
|
|
|
|
|
region, context))
|
2014-08-01 09:44:00 -04:00
|
|
|
return -1022;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case PROGRESSIVE_WBT_TILE_FIRST:
|
2019-12-10 16:19:20 +01:00
|
|
|
if (!progressive_tile_read(progressive, FALSE, s, blockType, blockLen, surface,
|
|
|
|
|
region, context))
|
2014-08-01 09:44:00 -04:00
|
|
|
return -1027;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case PROGRESSIVE_WBT_TILE_UPGRADE:
|
2019-12-10 16:19:20 +01:00
|
|
|
if (!progressive_tile_read_upgrade(progressive, s, blockType, blockLen, surface,
|
|
|
|
|
region, context))
|
2014-08-01 09:44:00 -04:00
|
|
|
return -1032;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
2023-07-28 18:45:58 +09:00
|
|
|
WLog_ERR(TAG, "Invalid block type %04" PRIx16 " (%s)", blockType,
|
2023-10-06 13:22:17 +02:00
|
|
|
rfx_get_progressive_block_type_string(blockType));
|
2014-08-01 09:44:00 -04:00
|
|
|
return -1039;
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-19 14:29:17 +02:00
|
|
|
size_t rem = Stream_GetPosition(s);
|
2019-12-10 16:19:20 +01:00
|
|
|
if ((rem - pos) != blockLen)
|
|
|
|
|
{
|
|
|
|
|
WLog_Print(progressive->log, WLOG_ERROR,
|
|
|
|
|
"Actual block read %" PRIuz " but expected %" PRIu32, rem - pos, blockLen);
|
2014-08-01 09:44:00 -04:00
|
|
|
return -1040;
|
2019-12-10 16:19:20 +01:00
|
|
|
}
|
2014-08-01 09:44:00 -04:00
|
|
|
count++;
|
2014-07-31 15:08:54 -04:00
|
|
|
}
|
2014-08-01 09:44:00 -04:00
|
|
|
|
2019-12-10 16:19:20 +01:00
|
|
|
end = Stream_GetPosition(s);
|
|
|
|
|
if ((end - start) != region->tileDataSize)
|
|
|
|
|
{
|
|
|
|
|
WLog_Print(progressive->log, WLOG_ERROR,
|
|
|
|
|
"Actual total blocks read %" PRIuz " but expected %" PRIu32, end - start,
|
|
|
|
|
region->tileDataSize);
|
2014-08-01 09:44:00 -04:00
|
|
|
return -1041;
|
2019-12-10 16:19:20 +01:00
|
|
|
}
|
2014-08-01 09:44:00 -04:00
|
|
|
|
2015-06-26 13:59:41 -04:00
|
|
|
if (count != region->numTiles)
|
|
|
|
|
{
|
2017-01-18 15:25:24 +01:00
|
|
|
WLog_Print(progressive->log, WLOG_WARN,
|
2019-11-06 15:24:51 +01:00
|
|
|
"numTiles inconsistency: actual: %" PRIu32 ", expected: %" PRIu16 "\n", count,
|
2017-01-18 15:25:24 +01:00
|
|
|
region->numTiles);
|
2019-12-10 16:19:20 +01:00
|
|
|
return -1044;
|
2015-06-26 13:59:41 -04:00
|
|
|
}
|
|
|
|
|
|
2024-05-08 15:10:42 +02:00
|
|
|
for (UINT32 idx = 0; idx < region->numTiles; idx++)
|
2014-07-31 15:08:54 -04:00
|
|
|
{
|
2024-05-08 15:10:42 +02:00
|
|
|
RFX_PROGRESSIVE_TILE* tile = region->tiles[idx];
|
2024-06-04 14:32:42 +02:00
|
|
|
PROGRESSIVE_TILE_PROCESS_WORK_PARAM* param = &progressive->params[idx];
|
2022-04-28 08:00:39 +02:00
|
|
|
param->progressive = progressive;
|
|
|
|
|
param->region = region;
|
|
|
|
|
param->context = context;
|
|
|
|
|
param->tile = tile;
|
2014-07-31 15:08:54 -04:00
|
|
|
|
2021-05-24 11:28:02 +02:00
|
|
|
if (progressive->rfx_context->priv->UseThreads)
|
2014-08-01 09:44:00 -04:00
|
|
|
{
|
2025-09-03 14:40:47 +02:00
|
|
|
progressive->work_objects[idx] = CreateThreadpoolWork(
|
2026-02-26 15:06:27 +01:00
|
|
|
progressive_process_tiles_tile_work_callback, (void*)param, nullptr);
|
2024-06-04 14:32:42 +02:00
|
|
|
if (!progressive->work_objects[idx])
|
2021-05-24 11:28:02 +02:00
|
|
|
{
|
2024-05-08 15:10:42 +02:00
|
|
|
WLog_Print(progressive->log, WLOG_ERROR,
|
|
|
|
|
"Failed to create ThreadpoolWork for tile %" PRIu32, idx);
|
2021-05-24 11:28:02 +02:00
|
|
|
status = -1;
|
2014-08-01 09:44:00 -04:00
|
|
|
break;
|
2021-05-24 11:28:02 +02:00
|
|
|
}
|
2014-08-01 09:44:00 -04:00
|
|
|
|
2024-06-04 14:32:42 +02:00
|
|
|
SubmitThreadpoolWork(progressive->work_objects[idx]);
|
2024-12-19 14:45:06 +01:00
|
|
|
|
|
|
|
|
close_cnt = WINPR_ASSERTING_INT_CAST(UINT16, idx + 1);
|
2021-05-24 11:28:02 +02:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2026-02-26 15:06:27 +01:00
|
|
|
progressive_process_tiles_tile_work_callback(nullptr, param, nullptr);
|
2014-08-01 09:44:00 -04:00
|
|
|
}
|
2014-08-28 15:14:01 -04:00
|
|
|
|
|
|
|
|
if (status < 0)
|
2019-12-10 16:19:20 +01:00
|
|
|
{
|
|
|
|
|
WLog_Print(progressive->log, WLOG_ERROR, "Failed to decompress %s at %" PRIu16,
|
2024-05-08 15:10:42 +02:00
|
|
|
rfx_get_progressive_block_type_string(tile->blockType), idx);
|
2022-04-28 08:00:39 +02:00
|
|
|
goto fail;
|
2019-12-10 16:19:20 +01:00
|
|
|
}
|
2014-07-31 15:08:54 -04:00
|
|
|
}
|
|
|
|
|
|
2021-05-24 11:28:02 +02:00
|
|
|
if (progressive->rfx_context->priv->UseThreads)
|
|
|
|
|
{
|
2024-05-08 15:10:42 +02:00
|
|
|
for (UINT32 idx = 0; idx < close_cnt; idx++)
|
2021-05-24 11:28:02 +02:00
|
|
|
{
|
2024-06-04 14:32:42 +02:00
|
|
|
WaitForThreadpoolWorkCallbacks(progressive->work_objects[idx], FALSE);
|
|
|
|
|
CloseThreadpoolWork(progressive->work_objects[idx]);
|
2021-05-24 11:28:02 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-28 08:00:39 +02:00
|
|
|
fail:
|
2021-05-24 11:28:02 +02:00
|
|
|
|
|
|
|
|
if (status < 0)
|
|
|
|
|
return -1;
|
|
|
|
|
|
2023-01-26 16:25:56 +01:00
|
|
|
return (SSIZE_T)(end - start);
|
2014-07-31 15:08:54 -04:00
|
|
|
}
|
|
|
|
|
|
2025-09-22 12:19:02 +02:00
|
|
|
static inline SSIZE_T progressive_wb_sync(PROGRESSIVE_CONTEXT* WINPR_RESTRICT progressive,
|
2024-05-29 23:53:33 +02:00
|
|
|
wStream* WINPR_RESTRICT s, UINT16 blockType,
|
|
|
|
|
UINT32 blockLen)
|
2014-07-28 17:42:23 -04:00
|
|
|
{
|
2019-12-10 16:19:20 +01:00
|
|
|
const UINT32 magic = 0xCACCACCA;
|
|
|
|
|
const UINT16 version = 0x0100;
|
2026-02-24 20:18:25 +01:00
|
|
|
PROGRESSIVE_BLOCK_SYNC sync = WINPR_C_ARRAY_INIT;
|
2019-12-10 16:19:20 +01:00
|
|
|
|
|
|
|
|
sync.blockType = blockType;
|
|
|
|
|
sync.blockLen = blockLen;
|
|
|
|
|
|
|
|
|
|
if (sync.blockLen != 12)
|
|
|
|
|
{
|
|
|
|
|
WLog_Print(progressive->log, WLOG_ERROR,
|
|
|
|
|
"PROGRESSIVE_BLOCK_SYNC::blockLen = 0x%08" PRIx32 " != 0x%08" PRIx32,
|
2025-08-13 09:00:25 +02:00
|
|
|
sync.blockLen, 12u);
|
2019-12-10 16:19:20 +01:00
|
|
|
return -1005;
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-19 14:29:17 +02:00
|
|
|
if (!Stream_CheckAndLogRequiredLength(TAG, s, 6))
|
2019-12-10 16:19:20 +01:00
|
|
|
return -1004;
|
|
|
|
|
|
2022-12-13 11:18:11 +01:00
|
|
|
#if defined(WITH_DEBUG_CODECS)
|
2019-12-10 16:19:20 +01:00
|
|
|
WLog_Print(progressive->log, WLOG_DEBUG, "ProgressiveSync");
|
2022-12-13 11:18:11 +01:00
|
|
|
#endif
|
2019-12-10 16:19:20 +01:00
|
|
|
|
|
|
|
|
Stream_Read_UINT32(s, sync.magic);
|
|
|
|
|
Stream_Read_UINT16(s, sync.version);
|
|
|
|
|
|
|
|
|
|
if (sync.magic != magic)
|
|
|
|
|
{
|
|
|
|
|
WLog_Print(progressive->log, WLOG_ERROR,
|
|
|
|
|
"PROGRESSIVE_BLOCK_SYNC::magic = 0x%08" PRIx32 " != 0x%08" PRIx32, sync.magic,
|
|
|
|
|
magic);
|
|
|
|
|
return -1005;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (sync.version != 0x0100)
|
|
|
|
|
{
|
|
|
|
|
WLog_Print(progressive->log, WLOG_ERROR,
|
|
|
|
|
"PROGRESSIVE_BLOCK_SYNC::version = 0x%04" PRIx16 " != 0x%04" PRIu16,
|
|
|
|
|
sync.version, version);
|
|
|
|
|
return -1006;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((progressive->state & FLAG_WBT_SYNC) != 0)
|
|
|
|
|
WLog_WARN(TAG, "Duplicate PROGRESSIVE_BLOCK_SYNC, ignoring");
|
|
|
|
|
|
|
|
|
|
progressive->state |= FLAG_WBT_SYNC;
|
2023-01-26 16:25:56 +01:00
|
|
|
return 0;
|
2019-12-10 16:19:20 +01:00
|
|
|
}
|
|
|
|
|
|
2025-09-22 12:19:02 +02:00
|
|
|
static inline SSIZE_T progressive_wb_frame_begin(PROGRESSIVE_CONTEXT* WINPR_RESTRICT progressive,
|
2024-05-29 23:53:33 +02:00
|
|
|
wStream* WINPR_RESTRICT s, UINT16 blockType,
|
|
|
|
|
UINT32 blockLen)
|
2019-12-10 16:19:20 +01:00
|
|
|
{
|
2026-02-24 20:18:25 +01:00
|
|
|
PROGRESSIVE_BLOCK_FRAME_BEGIN frameBegin = WINPR_C_ARRAY_INIT;
|
2019-12-10 16:19:20 +01:00
|
|
|
|
|
|
|
|
frameBegin.blockType = blockType;
|
|
|
|
|
frameBegin.blockLen = blockLen;
|
|
|
|
|
|
|
|
|
|
if (frameBegin.blockLen != 12)
|
|
|
|
|
{
|
|
|
|
|
WLog_Print(progressive->log, WLOG_ERROR,
|
|
|
|
|
" RFX_PROGRESSIVE_FRAME_BEGIN::blockLen = 0x%08" PRIx32 " != 0x%08" PRIx32,
|
2025-08-13 09:00:25 +02:00
|
|
|
frameBegin.blockLen, 12u);
|
2019-12-10 16:19:20 +01:00
|
|
|
return -1005;
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-19 14:29:17 +02:00
|
|
|
if (!Stream_CheckAndLogRequiredLength(TAG, s, 6))
|
2019-12-10 16:19:20 +01:00
|
|
|
return -1007;
|
|
|
|
|
|
|
|
|
|
Stream_Read_UINT32(s, frameBegin.frameIndex);
|
|
|
|
|
Stream_Read_UINT16(s, frameBegin.regionCount);
|
|
|
|
|
|
2022-12-13 11:18:11 +01:00
|
|
|
#if defined(WITH_DEBUG_CODECS)
|
2019-12-10 16:19:20 +01:00
|
|
|
WLog_Print(progressive->log, WLOG_DEBUG,
|
|
|
|
|
"ProgressiveFrameBegin: frameIndex: %" PRIu32 " regionCount: %" PRIu16 "",
|
|
|
|
|
frameBegin.frameIndex, frameBegin.regionCount);
|
2022-12-13 11:18:11 +01:00
|
|
|
#endif
|
|
|
|
|
|
2019-12-10 16:19:20 +01:00
|
|
|
/**
|
|
|
|
|
* If the number of elements specified by the regionCount field is
|
|
|
|
|
* larger than the actual number of elements in the regions field,
|
|
|
|
|
* the decoder SHOULD ignore this inconsistency.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
if ((progressive->state & FLAG_WBT_FRAME_BEGIN) != 0)
|
|
|
|
|
{
|
|
|
|
|
WLog_ERR(TAG, "Duplicate RFX_PROGRESSIVE_FRAME_BEGIN in stream, this is not allowed!");
|
|
|
|
|
return -1008;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((progressive->state & FLAG_WBT_FRAME_END) != 0)
|
|
|
|
|
{
|
|
|
|
|
WLog_ERR(TAG, "RFX_PROGRESSIVE_FRAME_BEGIN after RFX_PROGRESSIVE_FRAME_END in stream, this "
|
|
|
|
|
"is not allowed!");
|
|
|
|
|
return -1008;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
progressive->state |= FLAG_WBT_FRAME_BEGIN;
|
2023-01-26 16:25:56 +01:00
|
|
|
return 0;
|
2019-12-10 16:19:20 +01:00
|
|
|
}
|
|
|
|
|
|
2025-09-22 12:19:02 +02:00
|
|
|
static inline SSIZE_T progressive_wb_frame_end(PROGRESSIVE_CONTEXT* WINPR_RESTRICT progressive,
|
2024-05-29 23:53:33 +02:00
|
|
|
wStream* WINPR_RESTRICT s, UINT16 blockType,
|
|
|
|
|
UINT32 blockLen)
|
2019-12-10 16:19:20 +01:00
|
|
|
{
|
2026-02-24 20:18:25 +01:00
|
|
|
PROGRESSIVE_BLOCK_FRAME_END frameEnd = WINPR_C_ARRAY_INIT;
|
2019-12-10 16:19:20 +01:00
|
|
|
|
|
|
|
|
frameEnd.blockType = blockType;
|
|
|
|
|
frameEnd.blockLen = blockLen;
|
|
|
|
|
|
|
|
|
|
if (frameEnd.blockLen != 6)
|
|
|
|
|
{
|
|
|
|
|
WLog_Print(progressive->log, WLOG_ERROR,
|
|
|
|
|
" RFX_PROGRESSIVE_FRAME_END::blockLen = 0x%08" PRIx32 " != 0x%08" PRIx32,
|
2025-08-13 09:00:25 +02:00
|
|
|
frameEnd.blockLen, 6u);
|
2019-12-10 16:19:20 +01:00
|
|
|
return -1005;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (Stream_GetRemainingLength(s) != 0)
|
|
|
|
|
{
|
|
|
|
|
WLog_Print(progressive->log, WLOG_ERROR,
|
2025-08-13 09:00:25 +02:00
|
|
|
"ProgressiveFrameEnd short %" PRIuz ", expected %u",
|
|
|
|
|
Stream_GetRemainingLength(s), 0U);
|
2019-12-10 16:19:20 +01:00
|
|
|
return -1008;
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-13 11:18:11 +01:00
|
|
|
#if defined(WITH_DEBUG_CODECS)
|
2019-12-10 16:19:20 +01:00
|
|
|
WLog_Print(progressive->log, WLOG_DEBUG, "ProgressiveFrameEnd");
|
2022-12-13 11:18:11 +01:00
|
|
|
#endif
|
|
|
|
|
|
2019-12-10 16:19:20 +01:00
|
|
|
if ((progressive->state & FLAG_WBT_FRAME_BEGIN) == 0)
|
|
|
|
|
WLog_WARN(TAG, "RFX_PROGRESSIVE_FRAME_END before RFX_PROGRESSIVE_FRAME_BEGIN, ignoring");
|
|
|
|
|
if ((progressive->state & FLAG_WBT_FRAME_END) != 0)
|
|
|
|
|
WLog_WARN(TAG, "Duplicate RFX_PROGRESSIVE_FRAME_END, ignoring");
|
|
|
|
|
|
|
|
|
|
progressive->state |= FLAG_WBT_FRAME_END;
|
2023-01-26 16:25:56 +01:00
|
|
|
return 0;
|
2019-12-10 16:19:20 +01:00
|
|
|
}
|
|
|
|
|
|
2025-09-22 12:19:02 +02:00
|
|
|
static inline SSIZE_T progressive_wb_context(PROGRESSIVE_CONTEXT* WINPR_RESTRICT progressive,
|
2024-05-29 23:53:33 +02:00
|
|
|
wStream* WINPR_RESTRICT s, UINT16 blockType,
|
|
|
|
|
UINT32 blockLen)
|
2019-12-10 16:19:20 +01:00
|
|
|
{
|
|
|
|
|
PROGRESSIVE_BLOCK_CONTEXT* context = &progressive->context;
|
|
|
|
|
context->blockType = blockType;
|
|
|
|
|
context->blockLen = blockLen;
|
|
|
|
|
|
|
|
|
|
if (context->blockLen != 10)
|
|
|
|
|
{
|
|
|
|
|
WLog_Print(progressive->log, WLOG_ERROR,
|
2025-08-13 09:00:25 +02:00
|
|
|
"RFX_PROGRESSIVE_CONTEXT::blockLen = 0x%08" PRIx32 " != 0x%08x",
|
|
|
|
|
context->blockLen, 10u);
|
2019-12-10 16:19:20 +01:00
|
|
|
return -1005;
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-19 14:29:17 +02:00
|
|
|
if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
|
2019-12-10 16:19:20 +01:00
|
|
|
return -1009;
|
|
|
|
|
|
|
|
|
|
Stream_Read_UINT8(s, context->ctxId);
|
|
|
|
|
Stream_Read_UINT16(s, context->tileSize);
|
|
|
|
|
Stream_Read_UINT8(s, context->flags);
|
|
|
|
|
|
|
|
|
|
if (context->ctxId != 0x00)
|
|
|
|
|
WLog_WARN(TAG, "RFX_PROGRESSIVE_CONTEXT::ctxId != 0x00: %" PRIu8, context->ctxId);
|
|
|
|
|
|
|
|
|
|
if (context->tileSize != 64)
|
|
|
|
|
{
|
|
|
|
|
WLog_ERR(TAG, "RFX_PROGRESSIVE_CONTEXT::tileSize != 0x40: %" PRIu16, context->tileSize);
|
|
|
|
|
return -1010;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((progressive->state & FLAG_WBT_FRAME_BEGIN) != 0)
|
|
|
|
|
WLog_WARN(TAG, "RFX_PROGRESSIVE_CONTEXT received after RFX_PROGRESSIVE_FRAME_BEGIN");
|
|
|
|
|
if ((progressive->state & FLAG_WBT_FRAME_END) != 0)
|
|
|
|
|
WLog_WARN(TAG, "RFX_PROGRESSIVE_CONTEXT received after RFX_PROGRESSIVE_FRAME_END");
|
|
|
|
|
if ((progressive->state & FLAG_WBT_CONTEXT) != 0)
|
|
|
|
|
WLog_WARN(TAG, "Duplicate RFX_PROGRESSIVE_CONTEXT received, ignoring.");
|
|
|
|
|
|
2022-12-13 11:18:11 +01:00
|
|
|
#if defined(WITH_DEBUG_CODECS)
|
2019-12-10 16:19:20 +01:00
|
|
|
WLog_Print(progressive->log, WLOG_DEBUG, "ProgressiveContext: flags: 0x%02" PRIX8 "",
|
|
|
|
|
context->flags);
|
2022-12-13 11:18:11 +01:00
|
|
|
#endif
|
2019-12-10 16:19:20 +01:00
|
|
|
|
|
|
|
|
progressive->state |= FLAG_WBT_CONTEXT;
|
2023-01-26 16:25:56 +01:00
|
|
|
return 0;
|
2019-12-10 16:19:20 +01:00
|
|
|
}
|
|
|
|
|
|
2025-09-22 12:19:02 +02:00
|
|
|
static inline SSIZE_T
|
|
|
|
|
progressive_wb_read_region_header(PROGRESSIVE_CONTEXT* WINPR_RESTRICT progressive,
|
|
|
|
|
wStream* WINPR_RESTRICT s, UINT16 blockType, UINT32 blockLen,
|
|
|
|
|
PROGRESSIVE_BLOCK_REGION* WINPR_RESTRICT region)
|
2019-12-10 16:19:20 +01:00
|
|
|
{
|
2024-06-04 14:32:42 +02:00
|
|
|
region->usedTiles = 0;
|
2024-05-29 23:53:33 +02:00
|
|
|
|
2022-04-19 14:29:17 +02:00
|
|
|
if (!Stream_CheckAndLogRequiredLength(TAG, s, 12))
|
2019-12-10 16:19:20 +01:00
|
|
|
return -1011;
|
|
|
|
|
|
|
|
|
|
region->blockType = blockType;
|
|
|
|
|
region->blockLen = blockLen;
|
|
|
|
|
Stream_Read_UINT8(s, region->tileSize);
|
|
|
|
|
Stream_Read_UINT16(s, region->numRects);
|
|
|
|
|
Stream_Read_UINT8(s, region->numQuant);
|
|
|
|
|
Stream_Read_UINT8(s, region->numProgQuant);
|
|
|
|
|
Stream_Read_UINT8(s, region->flags);
|
|
|
|
|
Stream_Read_UINT16(s, region->numTiles);
|
|
|
|
|
Stream_Read_UINT32(s, region->tileDataSize);
|
|
|
|
|
|
|
|
|
|
if (region->tileSize != 64)
|
|
|
|
|
{
|
|
|
|
|
WLog_Print(progressive->log, WLOG_ERROR,
|
2025-08-13 09:00:25 +02:00
|
|
|
"ProgressiveRegion tile size %" PRIu8 ", expected %u", region->tileSize, 64U);
|
2019-12-10 16:19:20 +01:00
|
|
|
return -1012;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (region->numRects < 1)
|
|
|
|
|
{
|
|
|
|
|
WLog_Print(progressive->log, WLOG_ERROR, "ProgressiveRegion missing rect count %" PRIu16,
|
|
|
|
|
region->numRects);
|
|
|
|
|
return -1013;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (region->numQuant > 7)
|
|
|
|
|
{
|
|
|
|
|
WLog_Print(progressive->log, WLOG_ERROR,
|
2025-08-13 09:00:25 +02:00
|
|
|
"ProgressiveRegion quant count too high %" PRIu8 ", expected < %u",
|
|
|
|
|
region->numQuant, 7U);
|
2019-12-10 16:19:20 +01:00
|
|
|
return -1014;
|
|
|
|
|
}
|
|
|
|
|
|
2024-12-19 14:45:06 +01:00
|
|
|
const SSIZE_T rc = WINPR_ASSERTING_INT_CAST(SSIZE_T, Stream_GetRemainingLength(s));
|
2024-06-04 14:32:42 +02:00
|
|
|
const SSIZE_T expect = region->numRects * 8ll + region->numQuant * 5ll +
|
|
|
|
|
region->numProgQuant * 16ll + region->tileDataSize;
|
|
|
|
|
SSIZE_T len = rc;
|
|
|
|
|
if (expect != rc)
|
2019-12-10 16:19:20 +01:00
|
|
|
{
|
2024-06-04 14:32:42 +02:00
|
|
|
if (len / 8LL < region->numRects)
|
|
|
|
|
{
|
|
|
|
|
WLog_Print(progressive->log, WLOG_ERROR,
|
|
|
|
|
"ProgressiveRegion data short for region->rects");
|
|
|
|
|
return -1015;
|
|
|
|
|
}
|
|
|
|
|
len -= region->numRects * 8LL;
|
2019-12-10 16:19:20 +01:00
|
|
|
|
2024-06-04 14:32:42 +02:00
|
|
|
if (len / 5LL < region->numQuant)
|
|
|
|
|
{
|
|
|
|
|
WLog_Print(progressive->log, WLOG_ERROR,
|
|
|
|
|
"ProgressiveRegion data short for region->cQuant");
|
|
|
|
|
return -1018;
|
|
|
|
|
}
|
|
|
|
|
len -= region->numQuant * 5LL;
|
2019-12-10 16:19:20 +01:00
|
|
|
|
2024-06-04 14:32:42 +02:00
|
|
|
if (len / 16LL < region->numProgQuant)
|
|
|
|
|
{
|
|
|
|
|
WLog_Print(progressive->log, WLOG_ERROR,
|
|
|
|
|
"ProgressiveRegion data short for region->cProgQuant");
|
|
|
|
|
return -1021;
|
|
|
|
|
}
|
|
|
|
|
len -= region->numProgQuant * 16LL;
|
2019-12-10 16:19:20 +01:00
|
|
|
|
2024-06-04 14:32:42 +02:00
|
|
|
if (len < region->tileDataSize * 1ll)
|
|
|
|
|
{
|
|
|
|
|
WLog_Print(progressive->log, WLOG_ERROR,
|
|
|
|
|
"ProgressiveRegion data short for region->tiles");
|
|
|
|
|
return -1024;
|
|
|
|
|
}
|
|
|
|
|
len -= region->tileDataSize;
|
|
|
|
|
|
|
|
|
|
if (len > 0)
|
|
|
|
|
WLog_Print(progressive->log, WLOG_WARN,
|
|
|
|
|
"Unused bytes detected, %" PRIdz " bytes not processed", len);
|
2019-12-10 16:19:20 +01:00
|
|
|
}
|
2024-06-04 14:32:42 +02:00
|
|
|
|
|
|
|
|
return rc;
|
2019-12-10 16:19:20 +01:00
|
|
|
}
|
|
|
|
|
|
2025-09-22 12:19:02 +02:00
|
|
|
static inline SSIZE_T progressive_wb_skip_region(PROGRESSIVE_CONTEXT* WINPR_RESTRICT progressive,
|
2024-05-29 23:53:33 +02:00
|
|
|
wStream* WINPR_RESTRICT s, UINT16 blockType,
|
|
|
|
|
UINT32 blockLen)
|
2019-12-10 16:19:20 +01:00
|
|
|
{
|
2024-06-04 14:32:42 +02:00
|
|
|
PROGRESSIVE_BLOCK_REGION* WINPR_RESTRICT region = &progressive->region;
|
2019-12-10 16:19:20 +01:00
|
|
|
|
2024-06-04 14:32:42 +02:00
|
|
|
const SSIZE_T rc =
|
|
|
|
|
progressive_wb_read_region_header(progressive, s, blockType, blockLen, region);
|
2019-12-10 16:19:20 +01:00
|
|
|
if (rc < 0)
|
|
|
|
|
return rc;
|
|
|
|
|
|
2024-12-19 14:45:06 +01:00
|
|
|
if (!Stream_SafeSeek(s, WINPR_ASSERTING_INT_CAST(size_t, rc)))
|
2019-12-10 16:19:20 +01:00
|
|
|
return -1111;
|
|
|
|
|
|
2023-01-26 16:25:56 +01:00
|
|
|
return rc;
|
2019-12-10 16:19:20 +01:00
|
|
|
}
|
|
|
|
|
|
2025-09-22 12:19:02 +02:00
|
|
|
static inline SSIZE_T progressive_wb_region(PROGRESSIVE_CONTEXT* WINPR_RESTRICT progressive,
|
2024-05-29 23:53:33 +02:00
|
|
|
wStream* WINPR_RESTRICT s, UINT16 blockType,
|
|
|
|
|
UINT32 blockLen,
|
|
|
|
|
PROGRESSIVE_SURFACE_CONTEXT* WINPR_RESTRICT surface,
|
|
|
|
|
PROGRESSIVE_BLOCK_REGION* WINPR_RESTRICT region)
|
2019-12-10 16:19:20 +01:00
|
|
|
{
|
2023-01-26 16:25:56 +01:00
|
|
|
SSIZE_T rc = -1;
|
2024-01-23 16:49:54 +01:00
|
|
|
UINT16 boxLeft = 0;
|
|
|
|
|
UINT16 boxTop = 0;
|
|
|
|
|
UINT16 boxRight = 0;
|
|
|
|
|
UINT16 boxBottom = 0;
|
|
|
|
|
UINT16 idxLeft = 0;
|
|
|
|
|
UINT16 idxTop = 0;
|
|
|
|
|
UINT16 idxRight = 0;
|
|
|
|
|
UINT16 idxBottom = 0;
|
2019-12-10 16:19:20 +01:00
|
|
|
const PROGRESSIVE_BLOCK_CONTEXT* context = &progressive->context;
|
|
|
|
|
|
|
|
|
|
if ((progressive->state & FLAG_WBT_FRAME_BEGIN) == 0)
|
|
|
|
|
{
|
|
|
|
|
WLog_WARN(TAG, "RFX_PROGRESSIVE_REGION before RFX_PROGRESSIVE_FRAME_BEGIN, ignoring");
|
|
|
|
|
return progressive_wb_skip_region(progressive, s, blockType, blockLen);
|
|
|
|
|
}
|
|
|
|
|
if ((progressive->state & FLAG_WBT_FRAME_END) != 0)
|
|
|
|
|
{
|
|
|
|
|
WLog_WARN(TAG, "RFX_PROGRESSIVE_REGION after RFX_PROGRESSIVE_FRAME_END, ignoring");
|
|
|
|
|
return progressive_wb_skip_region(progressive, s, blockType, blockLen);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
progressive->state |= FLAG_WBT_REGION;
|
|
|
|
|
|
|
|
|
|
rc = progressive_wb_read_region_header(progressive, s, blockType, blockLen, region);
|
|
|
|
|
if (rc < 0)
|
|
|
|
|
return rc;
|
|
|
|
|
|
2023-01-26 16:25:56 +01:00
|
|
|
for (UINT16 index = 0; index < region->numRects; index++)
|
2019-12-10 16:19:20 +01:00
|
|
|
{
|
|
|
|
|
RFX_RECT* rect = &(region->rects[index]);
|
|
|
|
|
Stream_Read_UINT16(s, rect->x);
|
|
|
|
|
Stream_Read_UINT16(s, rect->y);
|
|
|
|
|
Stream_Read_UINT16(s, rect->width);
|
|
|
|
|
Stream_Read_UINT16(s, rect->height);
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-26 16:25:56 +01:00
|
|
|
for (BYTE index = 0; index < region->numQuant; index++)
|
2019-12-10 16:19:20 +01:00
|
|
|
{
|
|
|
|
|
RFX_COMPONENT_CODEC_QUANT* quantVal = &(region->quantVals[index]);
|
|
|
|
|
progressive_component_codec_quant_read(s, quantVal);
|
|
|
|
|
|
|
|
|
|
if (!progressive_rfx_quant_lcmp_greater_equal(quantVal, 6))
|
|
|
|
|
{
|
|
|
|
|
WLog_Print(progressive->log, WLOG_ERROR,
|
|
|
|
|
"ProgressiveRegion region->cQuant[%" PRIu32 "] < 6", index);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!progressive_rfx_quant_lcmp_less_equal(quantVal, 15))
|
|
|
|
|
{
|
|
|
|
|
WLog_Print(progressive->log, WLOG_ERROR,
|
|
|
|
|
"ProgressiveRegion region->cQuant[%" PRIu32 "] > 15", index);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-26 16:25:56 +01:00
|
|
|
for (BYTE index = 0; index < region->numProgQuant; index++)
|
2019-12-10 16:19:20 +01:00
|
|
|
{
|
|
|
|
|
RFX_PROGRESSIVE_CODEC_QUANT* quantProgVal = &(region->quantProgVals[index]);
|
|
|
|
|
|
|
|
|
|
Stream_Read_UINT8(s, quantProgVal->quality);
|
|
|
|
|
|
|
|
|
|
progressive_component_codec_quant_read(s, &(quantProgVal->yQuantValues));
|
|
|
|
|
progressive_component_codec_quant_read(s, &(quantProgVal->cbQuantValues));
|
|
|
|
|
progressive_component_codec_quant_read(s, &(quantProgVal->crQuantValues));
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-13 11:18:11 +01:00
|
|
|
#if defined(WITH_DEBUG_CODECS)
|
2019-12-10 16:19:20 +01:00
|
|
|
WLog_Print(progressive->log, WLOG_DEBUG,
|
|
|
|
|
"ProgressiveRegion: numRects: %" PRIu16 " numTiles: %" PRIu16
|
|
|
|
|
" tileDataSize: %" PRIu32 " flags: 0x%02" PRIX8 " numQuant: %" PRIu8
|
|
|
|
|
" numProgQuant: %" PRIu8 "",
|
|
|
|
|
region->numRects, region->numTiles, region->tileDataSize, region->flags,
|
|
|
|
|
region->numQuant, region->numProgQuant);
|
2022-12-13 11:18:11 +01:00
|
|
|
#endif
|
2019-12-10 16:19:20 +01:00
|
|
|
|
2024-12-19 14:45:06 +01:00
|
|
|
boxLeft = WINPR_ASSERTING_INT_CAST(UINT16, surface->gridWidth);
|
|
|
|
|
boxTop = WINPR_ASSERTING_INT_CAST(UINT16, surface->gridHeight);
|
2019-12-10 16:19:20 +01:00
|
|
|
boxRight = 0;
|
|
|
|
|
boxBottom = 0;
|
|
|
|
|
|
2023-01-26 16:25:56 +01:00
|
|
|
for (UINT16 index = 0; index < region->numRects; index++)
|
2019-12-10 16:19:20 +01:00
|
|
|
{
|
|
|
|
|
RFX_RECT* rect = &(region->rects[index]);
|
|
|
|
|
idxLeft = rect->x / 64;
|
|
|
|
|
idxTop = rect->y / 64;
|
|
|
|
|
idxRight = (rect->x + rect->width + 63) / 64;
|
|
|
|
|
idxBottom = (rect->y + rect->height + 63) / 64;
|
|
|
|
|
|
|
|
|
|
if (idxLeft < boxLeft)
|
|
|
|
|
boxLeft = idxLeft;
|
|
|
|
|
|
|
|
|
|
if (idxTop < boxTop)
|
|
|
|
|
boxTop = idxTop;
|
|
|
|
|
|
|
|
|
|
if (idxRight > boxRight)
|
|
|
|
|
boxRight = idxRight;
|
|
|
|
|
|
|
|
|
|
if (idxBottom > boxBottom)
|
|
|
|
|
boxBottom = idxBottom;
|
|
|
|
|
|
2022-12-13 11:18:11 +01:00
|
|
|
#if defined(WITH_DEBUG_CODECS)
|
2019-12-10 16:19:20 +01:00
|
|
|
WLog_Print(progressive->log, WLOG_DEBUG,
|
|
|
|
|
"rect[%" PRIu16 "]: x: %" PRIu16 " y: %" PRIu16 " w: %" PRIu16 " h: %" PRIu16 "",
|
|
|
|
|
index, rect->x, rect->y, rect->width, rect->height);
|
2022-12-13 11:18:11 +01:00
|
|
|
#endif
|
2019-12-10 16:19:20 +01:00
|
|
|
}
|
|
|
|
|
|
2023-01-26 16:25:56 +01:00
|
|
|
const SSIZE_T res = progressive_process_tiles(progressive, s, region, surface, context);
|
|
|
|
|
if (res < 0)
|
|
|
|
|
return -1;
|
2024-12-19 14:45:06 +01:00
|
|
|
return rc;
|
2023-01-26 16:25:56 +01:00
|
|
|
}
|
|
|
|
|
|
2025-09-22 12:19:02 +02:00
|
|
|
static inline SSIZE_T progressive_parse_block(PROGRESSIVE_CONTEXT* WINPR_RESTRICT progressive,
|
2024-06-04 14:32:42 +02:00
|
|
|
wStream* WINPR_RESTRICT s,
|
|
|
|
|
PROGRESSIVE_SURFACE_CONTEXT* WINPR_RESTRICT surface,
|
|
|
|
|
PROGRESSIVE_BLOCK_REGION* WINPR_RESTRICT region)
|
2023-01-26 16:25:56 +01:00
|
|
|
{
|
2024-01-23 16:49:54 +01:00
|
|
|
UINT16 blockType = 0;
|
|
|
|
|
UINT32 blockLen = 0;
|
2023-01-26 16:25:56 +01:00
|
|
|
SSIZE_T rc = -1;
|
2026-02-24 20:18:25 +01:00
|
|
|
wStream sub = WINPR_C_ARRAY_INIT;
|
2023-01-26 16:25:56 +01:00
|
|
|
|
|
|
|
|
WINPR_ASSERT(progressive);
|
|
|
|
|
|
|
|
|
|
if (!Stream_CheckAndLogRequiredLength(TAG, s, 6))
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
Stream_Read_UINT16(s, blockType);
|
|
|
|
|
Stream_Read_UINT32(s, blockLen);
|
|
|
|
|
|
|
|
|
|
if (blockLen < 6)
|
|
|
|
|
{
|
|
|
|
|
WLog_WARN(TAG, "Invalid blockLen %" PRIu32 ", expected >= 6", blockLen);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
if (!Stream_CheckAndLogRequiredLength(TAG, s, blockLen - 6))
|
|
|
|
|
return -1;
|
|
|
|
|
Stream_StaticConstInit(&sub, Stream_Pointer(s), blockLen - 6);
|
|
|
|
|
Stream_Seek(s, blockLen - 6);
|
|
|
|
|
|
|
|
|
|
switch (blockType)
|
|
|
|
|
{
|
|
|
|
|
case PROGRESSIVE_WBT_SYNC:
|
|
|
|
|
rc = progressive_wb_sync(progressive, &sub, blockType, blockLen);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case PROGRESSIVE_WBT_FRAME_BEGIN:
|
|
|
|
|
rc = progressive_wb_frame_begin(progressive, &sub, blockType, blockLen);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case PROGRESSIVE_WBT_FRAME_END:
|
|
|
|
|
rc = progressive_wb_frame_end(progressive, &sub, blockType, blockLen);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case PROGRESSIVE_WBT_CONTEXT:
|
|
|
|
|
rc = progressive_wb_context(progressive, &sub, blockType, blockLen);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case PROGRESSIVE_WBT_REGION:
|
|
|
|
|
rc = progressive_wb_region(progressive, &sub, blockType, blockLen, surface, region);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
WLog_Print(progressive->log, WLOG_ERROR, "Invalid block type %04" PRIx16, blockType);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (rc < 0)
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
if (Stream_GetRemainingLength(&sub) > 0)
|
|
|
|
|
{
|
|
|
|
|
WLog_Print(progressive->log, WLOG_ERROR,
|
|
|
|
|
"block len %" PRIu32 " does not match read data %" PRIuz, blockLen,
|
|
|
|
|
blockLen - Stream_GetRemainingLength(&sub));
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return rc;
|
2019-12-10 16:19:20 +01:00
|
|
|
}
|
|
|
|
|
|
2025-09-22 12:19:02 +02:00
|
|
|
static inline BOOL update_tiles(PROGRESSIVE_CONTEXT* WINPR_RESTRICT progressive,
|
2024-06-04 14:32:42 +02:00
|
|
|
PROGRESSIVE_SURFACE_CONTEXT* WINPR_RESTRICT surface,
|
|
|
|
|
BYTE* WINPR_RESTRICT pDstData, UINT32 DstFormat, UINT32 nDstStep,
|
|
|
|
|
UINT32 nXDst, UINT32 nYDst,
|
|
|
|
|
PROGRESSIVE_BLOCK_REGION* WINPR_RESTRICT region,
|
|
|
|
|
REGION16* WINPR_RESTRICT invalidRegion)
|
2019-12-10 16:19:20 +01:00
|
|
|
{
|
2024-04-18 12:22:44 +02:00
|
|
|
BOOL rc = TRUE;
|
2026-02-24 20:18:25 +01:00
|
|
|
REGION16 clippingRects = WINPR_C_ARRAY_INIT;
|
2016-04-05 17:07:45 +02:00
|
|
|
region16_init(&clippingRects);
|
|
|
|
|
|
2023-05-08 09:23:01 +02:00
|
|
|
for (UINT32 i = 0; i < region->numRects; i++)
|
2016-04-05 17:07:45 +02:00
|
|
|
{
|
2026-02-24 20:18:25 +01:00
|
|
|
RECTANGLE_16 clippingRect = WINPR_C_ARRAY_INIT;
|
2016-07-14 17:55:53 +02:00
|
|
|
const RFX_RECT* rect = &(region->rects[i]);
|
2023-05-08 09:23:01 +02:00
|
|
|
|
2022-04-06 10:10:07 +02:00
|
|
|
clippingRect.left = (UINT16)nXDst + rect->x;
|
|
|
|
|
clippingRect.top = (UINT16)nYDst + rect->y;
|
2016-04-05 17:07:45 +02:00
|
|
|
clippingRect.right = clippingRect.left + rect->width;
|
|
|
|
|
clippingRect.bottom = clippingRect.top + rect->height;
|
2026-02-16 10:57:57 +01:00
|
|
|
if (!region16_union_rect(&clippingRects, &clippingRects, &clippingRect))
|
|
|
|
|
{
|
|
|
|
|
region16_uninit(&clippingRects);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
2016-04-05 17:07:45 +02:00
|
|
|
}
|
|
|
|
|
|
2023-05-08 09:23:01 +02:00
|
|
|
for (UINT32 i = 0; i < surface->numUpdatedTiles; i++)
|
2016-04-05 17:07:45 +02:00
|
|
|
{
|
2023-05-08 09:23:01 +02:00
|
|
|
UINT32 nbUpdateRects = 0;
|
2026-02-26 15:06:27 +01:00
|
|
|
const RECTANGLE_16* updateRects = nullptr;
|
2026-02-24 20:18:25 +01:00
|
|
|
RECTANGLE_16 updateRect = WINPR_C_ARRAY_INIT;
|
2023-05-08 09:23:01 +02:00
|
|
|
|
|
|
|
|
WINPR_ASSERT(surface->updatedTileIndices);
|
|
|
|
|
const UINT32 index = surface->updatedTileIndices[i];
|
|
|
|
|
|
|
|
|
|
WINPR_ASSERT(index < surface->tilesSize);
|
|
|
|
|
RFX_PROGRESSIVE_TILE* tile = surface->tiles[index];
|
|
|
|
|
WINPR_ASSERT(tile);
|
2019-12-10 16:19:20 +01:00
|
|
|
|
2024-12-19 14:45:06 +01:00
|
|
|
const UINT32 dl = nXDst + tile->x;
|
|
|
|
|
updateRect.left = WINPR_ASSERTING_INT_CAST(UINT16, dl);
|
|
|
|
|
|
|
|
|
|
const UINT32 dt = nYDst + tile->y;
|
|
|
|
|
updateRect.top = WINPR_ASSERTING_INT_CAST(UINT16, dt);
|
2016-04-05 17:07:45 +02:00
|
|
|
updateRect.right = updateRect.left + 64;
|
|
|
|
|
updateRect.bottom = updateRect.top + 64;
|
2023-05-08 09:23:01 +02:00
|
|
|
|
2026-02-24 20:18:25 +01:00
|
|
|
REGION16 updateRegion = WINPR_C_ARRAY_INIT;
|
2016-04-05 17:07:45 +02:00
|
|
|
region16_init(&updateRegion);
|
2026-02-16 10:57:57 +01:00
|
|
|
if (!region16_intersect_rect(&updateRegion, &clippingRects, &updateRect))
|
|
|
|
|
{
|
|
|
|
|
region16_uninit(&updateRegion);
|
|
|
|
|
goto fail;
|
|
|
|
|
}
|
2016-04-05 17:07:45 +02:00
|
|
|
updateRects = region16_rects(&updateRegion, &nbUpdateRects);
|
|
|
|
|
|
2023-05-08 09:23:01 +02:00
|
|
|
for (UINT32 j = 0; j < nbUpdateRects; j++)
|
2016-04-05 17:07:45 +02:00
|
|
|
{
|
2025-03-13 08:38:06 +01:00
|
|
|
rc = FALSE;
|
2016-07-14 17:55:53 +02:00
|
|
|
const RECTANGLE_16* rect = &updateRects[j];
|
2023-08-22 15:05:20 +02:00
|
|
|
if (rect->left < updateRect.left)
|
2025-03-13 08:38:06 +01:00
|
|
|
break;
|
2023-08-22 15:05:20 +02:00
|
|
|
const UINT32 nXSrc = rect->left - updateRect.left;
|
|
|
|
|
const UINT32 nYSrc = rect->top - updateRect.top;
|
2016-07-14 17:55:53 +02:00
|
|
|
const UINT32 width = rect->right - rect->left;
|
|
|
|
|
const UINT32 height = rect->bottom - rect->top;
|
|
|
|
|
|
2023-08-22 15:05:20 +02:00
|
|
|
if (rect->left + width > surface->width)
|
2025-03-13 08:38:06 +01:00
|
|
|
break;
|
2023-08-22 15:05:20 +02:00
|
|
|
if (rect->top + height > surface->height)
|
2025-03-13 08:38:06 +01:00
|
|
|
break;
|
2024-05-23 10:07:14 +02:00
|
|
|
rc = freerdp_image_copy_no_overlap(
|
|
|
|
|
pDstData, DstFormat, nDstStep, rect->left, rect->top, width, height, tile->data,
|
2026-02-26 15:06:27 +01:00
|
|
|
progressive->format, tile->stride, nXSrc, nYSrc, nullptr, FREERDP_KEEP_DST_ALPHA);
|
2024-04-18 12:22:44 +02:00
|
|
|
if (!rc)
|
2016-04-23 11:25:55 +02:00
|
|
|
break;
|
2017-04-03 18:59:58 +02:00
|
|
|
|
|
|
|
|
if (invalidRegion)
|
2026-02-16 10:57:57 +01:00
|
|
|
{
|
|
|
|
|
if (!region16_union_rect(invalidRegion, invalidRegion, rect))
|
|
|
|
|
{
|
|
|
|
|
region16_uninit(&updateRegion);
|
|
|
|
|
goto fail;
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-04-05 17:07:45 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
region16_uninit(&updateRegion);
|
2025-03-13 08:38:06 +01:00
|
|
|
if (!rc)
|
|
|
|
|
goto fail;
|
2023-05-09 23:33:52 +02:00
|
|
|
tile->dirty = FALSE;
|
2016-04-05 17:07:45 +02:00
|
|
|
}
|
|
|
|
|
|
2024-04-18 12:22:44 +02:00
|
|
|
fail:
|
2016-04-05 17:07:45 +02:00
|
|
|
region16_uninit(&clippingRects);
|
2024-04-18 12:22:44 +02:00
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-29 23:53:33 +02:00
|
|
|
INT32 progressive_decompress(PROGRESSIVE_CONTEXT* WINPR_RESTRICT progressive,
|
|
|
|
|
const BYTE* WINPR_RESTRICT pSrcData, UINT32 SrcSize,
|
|
|
|
|
BYTE* WINPR_RESTRICT pDstData, UINT32 DstFormat, UINT32 nDstStep,
|
|
|
|
|
UINT32 nXDst, UINT32 nYDst, REGION16* WINPR_RESTRICT invalidRegion,
|
|
|
|
|
UINT16 surfaceId, UINT32 frameId)
|
2024-04-18 12:22:44 +02:00
|
|
|
{
|
|
|
|
|
INT32 rc = 1;
|
|
|
|
|
|
|
|
|
|
WINPR_ASSERT(progressive);
|
|
|
|
|
PROGRESSIVE_SURFACE_CONTEXT* surface = progressive_get_surface_data(progressive, surfaceId);
|
|
|
|
|
|
|
|
|
|
if (!surface)
|
|
|
|
|
{
|
|
|
|
|
WLog_Print(progressive->log, WLOG_ERROR, "ProgressiveRegion no surface for %" PRIu16,
|
|
|
|
|
surfaceId);
|
|
|
|
|
return -1001;
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-04 14:32:42 +02:00
|
|
|
PROGRESSIVE_BLOCK_REGION* WINPR_RESTRICT region = &progressive->region;
|
2024-04-18 12:22:44 +02:00
|
|
|
WINPR_ASSERT(region);
|
|
|
|
|
|
|
|
|
|
if (surface->frameId != frameId)
|
|
|
|
|
{
|
|
|
|
|
surface->frameId = frameId;
|
|
|
|
|
surface->numUpdatedTiles = 0;
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-24 20:18:25 +01:00
|
|
|
wStream ss = WINPR_C_ARRAY_INIT;
|
2024-04-18 12:22:44 +02:00
|
|
|
wStream* s = Stream_StaticConstInit(&ss, pSrcData, SrcSize);
|
|
|
|
|
WINPR_ASSERT(s);
|
|
|
|
|
|
|
|
|
|
switch (DstFormat)
|
|
|
|
|
{
|
|
|
|
|
case PIXEL_FORMAT_RGBA32:
|
|
|
|
|
case PIXEL_FORMAT_RGBX32:
|
|
|
|
|
case PIXEL_FORMAT_BGRA32:
|
|
|
|
|
case PIXEL_FORMAT_BGRX32:
|
|
|
|
|
progressive->format = DstFormat;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
progressive->format = PIXEL_FORMAT_XRGB32;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const size_t start = Stream_GetPosition(s);
|
|
|
|
|
progressive->state = 0; /* Set state to not initialized */
|
|
|
|
|
while (Stream_GetRemainingLength(s) > 0)
|
|
|
|
|
{
|
|
|
|
|
if (progressive_parse_block(progressive, s, surface, region) < 0)
|
|
|
|
|
goto fail;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
{
|
2026-01-08 10:32:29 +01:00
|
|
|
const size_t end = Stream_GetPosition(s);
|
|
|
|
|
if ((end - start) != SrcSize)
|
|
|
|
|
{
|
|
|
|
|
WLog_Print(progressive->log, WLOG_ERROR,
|
|
|
|
|
"total block len %" PRIuz " does not match read data %" PRIu32, end - start,
|
|
|
|
|
SrcSize);
|
|
|
|
|
rc = -1041;
|
|
|
|
|
goto fail;
|
|
|
|
|
}
|
2024-04-18 12:22:44 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!update_tiles(progressive, surface, pDstData, DstFormat, nDstStep, nXDst, nYDst, region,
|
|
|
|
|
invalidRegion))
|
|
|
|
|
return -2002;
|
2019-12-10 16:19:20 +01:00
|
|
|
fail:
|
2016-04-23 11:25:55 +02:00
|
|
|
return rc;
|
2014-07-28 17:42:23 -04:00
|
|
|
}
|
|
|
|
|
|
2025-03-10 18:17:49 +01:00
|
|
|
BOOL progressive_rfx_write_message_progressive_simple(
|
|
|
|
|
PROGRESSIVE_CONTEXT* WINPR_RESTRICT progressive, wStream* WINPR_RESTRICT s,
|
|
|
|
|
const RFX_MESSAGE* WINPR_RESTRICT msg)
|
2020-12-15 09:58:37 +01:00
|
|
|
{
|
2026-02-26 15:06:27 +01:00
|
|
|
RFX_CONTEXT* context = nullptr;
|
2020-12-15 09:58:37 +01:00
|
|
|
|
2021-06-28 14:45:19 +02:00
|
|
|
WINPR_ASSERT(progressive);
|
|
|
|
|
WINPR_ASSERT(s);
|
|
|
|
|
WINPR_ASSERT(msg);
|
|
|
|
|
context = progressive->rfx_context;
|
2023-10-06 13:22:17 +02:00
|
|
|
return rfx_write_message_progressive_simple(context, s, msg);
|
2020-12-15 09:58:37 +01:00
|
|
|
}
|
|
|
|
|
|
2024-09-12 12:52:21 +02:00
|
|
|
int progressive_compress(PROGRESSIVE_CONTEXT* WINPR_RESTRICT progressive,
|
|
|
|
|
const BYTE* WINPR_RESTRICT pSrcData, UINT32 SrcSize, UINT32 SrcFormat,
|
|
|
|
|
UINT32 Width, UINT32 Height, UINT32 ScanLine,
|
|
|
|
|
const REGION16* WINPR_RESTRICT invalidRegion,
|
|
|
|
|
BYTE** WINPR_RESTRICT ppDstData, UINT32* WINPR_RESTRICT pDstSize)
|
2014-07-28 17:42:23 -04:00
|
|
|
{
|
2023-06-05 12:16:57 +02:00
|
|
|
BOOL rc = FALSE;
|
2020-12-15 09:58:37 +01:00
|
|
|
int res = -6;
|
2026-02-26 15:06:27 +01:00
|
|
|
wStream* s = nullptr;
|
2024-01-23 16:49:54 +01:00
|
|
|
UINT32 numRects = 0;
|
2026-02-26 15:06:27 +01:00
|
|
|
RFX_RECT* rects = nullptr;
|
|
|
|
|
RFX_MESSAGE* message = nullptr;
|
2020-12-15 09:58:37 +01:00
|
|
|
|
2020-12-15 16:02:34 +01:00
|
|
|
if (!progressive || !pSrcData || !ppDstData || !pDstSize)
|
2020-12-15 09:58:37 +01:00
|
|
|
{
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ScanLine == 0)
|
|
|
|
|
{
|
|
|
|
|
switch (SrcFormat)
|
|
|
|
|
{
|
|
|
|
|
case PIXEL_FORMAT_ABGR32:
|
|
|
|
|
case PIXEL_FORMAT_ARGB32:
|
|
|
|
|
case PIXEL_FORMAT_XBGR32:
|
|
|
|
|
case PIXEL_FORMAT_XRGB32:
|
|
|
|
|
case PIXEL_FORMAT_BGRA32:
|
|
|
|
|
case PIXEL_FORMAT_BGRX32:
|
|
|
|
|
case PIXEL_FORMAT_RGBA32:
|
|
|
|
|
case PIXEL_FORMAT_RGBX32:
|
|
|
|
|
ScanLine = Width * 4;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
return -2;
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-06-28 14:45:19 +02:00
|
|
|
|
2020-12-15 09:58:37 +01:00
|
|
|
if (SrcSize < Height * ScanLine)
|
|
|
|
|
return -4;
|
|
|
|
|
|
2020-12-15 16:02:34 +01:00
|
|
|
if (!invalidRegion)
|
|
|
|
|
{
|
|
|
|
|
numRects = (Width + 63) / 64;
|
|
|
|
|
numRects *= (Height + 63) / 64;
|
|
|
|
|
}
|
|
|
|
|
else
|
2024-12-19 14:45:06 +01:00
|
|
|
{
|
|
|
|
|
const int nr = region16_n_rects(invalidRegion);
|
|
|
|
|
numRects = WINPR_ASSERTING_INT_CAST(uint32_t, nr);
|
|
|
|
|
}
|
2020-12-15 16:02:34 +01:00
|
|
|
|
|
|
|
|
if (numRects == 0)
|
|
|
|
|
return 0;
|
|
|
|
|
|
2025-01-10 14:27:58 +01:00
|
|
|
if (!Stream_EnsureRemainingCapacity(progressive->rects, numRects * sizeof(RFX_RECT)))
|
2020-12-15 09:58:37 +01:00
|
|
|
return -5;
|
2024-10-01 10:34:14 +02:00
|
|
|
rects = Stream_BufferAs(progressive->rects, RFX_RECT);
|
2020-12-15 16:02:34 +01:00
|
|
|
if (invalidRegion)
|
|
|
|
|
{
|
2026-02-26 15:06:27 +01:00
|
|
|
const RECTANGLE_16* region_rects = region16_rects(invalidRegion, nullptr);
|
2024-05-08 15:10:42 +02:00
|
|
|
for (UINT32 idx = 0; idx < numRects; idx++)
|
2020-12-15 16:02:34 +01:00
|
|
|
{
|
2024-05-08 15:10:42 +02:00
|
|
|
const RECTANGLE_16* r = ®ion_rects[idx];
|
|
|
|
|
RFX_RECT* rect = &rects[idx];
|
2021-06-28 14:45:19 +02:00
|
|
|
|
|
|
|
|
rect->x = r->left;
|
|
|
|
|
rect->y = r->top;
|
|
|
|
|
rect->width = r->right - r->left;
|
|
|
|
|
rect->height = r->bottom - r->top;
|
2020-12-15 16:02:34 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2024-12-19 14:45:06 +01:00
|
|
|
UINT16 x = 0;
|
|
|
|
|
UINT16 y = 0;
|
|
|
|
|
|
2024-01-30 10:25:38 +01:00
|
|
|
for (UINT32 i = 0; i < numRects; i++)
|
2020-12-15 16:02:34 +01:00
|
|
|
{
|
|
|
|
|
RFX_RECT* r = &rects[i];
|
|
|
|
|
r->x = x;
|
|
|
|
|
r->y = y;
|
2024-12-19 14:45:06 +01:00
|
|
|
|
|
|
|
|
WINPR_ASSERT(Width >= x);
|
|
|
|
|
WINPR_ASSERT(Height >= y);
|
|
|
|
|
r->width = MIN(64, WINPR_ASSERTING_INT_CAST(UINT16, Width - x));
|
|
|
|
|
r->height = MIN(64, WINPR_ASSERTING_INT_CAST(UINT16, Height - y));
|
2020-12-15 16:02:34 +01:00
|
|
|
|
2025-03-10 19:18:23 +01:00
|
|
|
if (x + 64UL >= Width)
|
2020-12-15 16:02:34 +01:00
|
|
|
{
|
|
|
|
|
y += 64;
|
|
|
|
|
x = 0;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
x += 64;
|
2021-07-01 08:08:27 +02:00
|
|
|
|
|
|
|
|
WINPR_ASSERT(r->x % 64 == 0);
|
|
|
|
|
WINPR_ASSERT(r->y % 64 == 0);
|
2021-07-28 09:09:07 +02:00
|
|
|
WINPR_ASSERT(r->width <= 64);
|
|
|
|
|
WINPR_ASSERT(r->height <= 64);
|
2020-12-15 16:02:34 +01:00
|
|
|
}
|
|
|
|
|
}
|
2020-12-15 09:58:37 +01:00
|
|
|
s = progressive->buffer;
|
2026-02-27 20:04:43 +01:00
|
|
|
Stream_ResetPosition(s);
|
2020-12-15 09:58:37 +01:00
|
|
|
|
|
|
|
|
progressive->rfx_context->mode = RLGR1;
|
2024-12-19 14:45:06 +01:00
|
|
|
|
|
|
|
|
progressive->rfx_context->width = WINPR_ASSERTING_INT_CAST(UINT16, Width);
|
|
|
|
|
progressive->rfx_context->height = WINPR_ASSERTING_INT_CAST(UINT16, Height);
|
2021-06-28 14:45:19 +02:00
|
|
|
rfx_context_set_pixel_format(progressive->rfx_context, SrcFormat);
|
2020-12-15 09:58:37 +01:00
|
|
|
message = rfx_encode_message(progressive->rfx_context, rects, numRects, pSrcData, Width, Height,
|
|
|
|
|
ScanLine);
|
|
|
|
|
if (!message)
|
|
|
|
|
{
|
|
|
|
|
WLog_ERR(TAG, "failed to encode rfx message");
|
|
|
|
|
goto fail;
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-28 14:45:19 +02:00
|
|
|
rc = progressive_rfx_write_message_progressive_simple(progressive, s, message);
|
2020-12-15 09:58:37 +01:00
|
|
|
rfx_message_free(progressive->rfx_context, message);
|
|
|
|
|
if (!rc)
|
|
|
|
|
goto fail;
|
|
|
|
|
|
2026-01-08 10:32:29 +01:00
|
|
|
{
|
|
|
|
|
const size_t pos = Stream_GetPosition(s);
|
|
|
|
|
WINPR_ASSERT(pos <= UINT32_MAX);
|
|
|
|
|
*pDstSize = (UINT32)pos;
|
|
|
|
|
}
|
2020-12-15 09:58:37 +01:00
|
|
|
*ppDstData = Stream_Buffer(s);
|
2021-06-28 14:45:19 +02:00
|
|
|
res = 1;
|
2020-12-15 09:58:37 +01:00
|
|
|
fail:
|
|
|
|
|
return res;
|
2014-07-28 17:42:23 -04:00
|
|
|
}
|
|
|
|
|
|
2024-09-12 12:52:21 +02:00
|
|
|
BOOL progressive_context_reset(PROGRESSIVE_CONTEXT* WINPR_RESTRICT progressive)
|
2014-07-28 17:42:23 -04:00
|
|
|
{
|
2026-02-26 15:06:27 +01:00
|
|
|
return (progressive != nullptr);
|
2014-07-28 17:42:23 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PROGRESSIVE_CONTEXT* progressive_context_new(BOOL Compressor)
|
2023-03-20 14:51:52 +01:00
|
|
|
{
|
|
|
|
|
return progressive_context_new_ex(Compressor, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PROGRESSIVE_CONTEXT* progressive_context_new_ex(BOOL Compressor, UINT32 ThreadingFlags)
|
2014-07-28 17:42:23 -04:00
|
|
|
{
|
2023-03-24 12:44:04 +01:00
|
|
|
PROGRESSIVE_CONTEXT* progressive =
|
|
|
|
|
(PROGRESSIVE_CONTEXT*)winpr_aligned_calloc(1, sizeof(PROGRESSIVE_CONTEXT), 32);
|
2014-07-28 17:42:23 -04:00
|
|
|
|
2020-12-15 09:58:37 +01:00
|
|
|
if (!progressive)
|
2026-02-26 15:06:27 +01:00
|
|
|
return nullptr;
|
2014-07-29 17:37:46 -04:00
|
|
|
|
2020-12-15 09:58:37 +01:00
|
|
|
progressive->Compressor = Compressor;
|
|
|
|
|
progressive->quantProgValFull.quality = 100;
|
|
|
|
|
progressive->log = WLog_Get(TAG);
|
|
|
|
|
if (!progressive->log)
|
|
|
|
|
goto fail;
|
2023-03-20 14:51:52 +01:00
|
|
|
progressive->rfx_context = rfx_context_new_ex(Compressor, ThreadingFlags);
|
2020-12-15 09:58:37 +01:00
|
|
|
if (!progressive->rfx_context)
|
|
|
|
|
goto fail;
|
2026-02-26 15:06:27 +01:00
|
|
|
progressive->buffer = Stream_New(nullptr, 1024);
|
2020-12-15 09:58:37 +01:00
|
|
|
if (!progressive->buffer)
|
|
|
|
|
goto fail;
|
2026-02-26 15:06:27 +01:00
|
|
|
progressive->rects = Stream_New(nullptr, 1024);
|
2020-12-15 09:58:37 +01:00
|
|
|
if (!progressive->rects)
|
|
|
|
|
goto fail;
|
2024-08-26 16:33:59 +02:00
|
|
|
progressive->bufferPool = BufferPool_New(TRUE, (8192LL + 32LL) * 3LL, 16);
|
2020-12-15 09:58:37 +01:00
|
|
|
if (!progressive->bufferPool)
|
|
|
|
|
goto fail;
|
|
|
|
|
progressive->SurfaceContexts = HashTable_New(TRUE);
|
|
|
|
|
if (!progressive->SurfaceContexts)
|
|
|
|
|
goto fail;
|
2014-07-28 17:42:23 -04:00
|
|
|
|
2022-04-06 10:10:07 +02:00
|
|
|
{
|
|
|
|
|
wObject* obj = HashTable_ValueObject(progressive->SurfaceContexts);
|
|
|
|
|
WINPR_ASSERT(obj);
|
|
|
|
|
obj->fnObjectFree = progressive_surface_context_free;
|
|
|
|
|
}
|
2014-07-28 17:42:23 -04:00
|
|
|
return progressive;
|
2020-12-15 09:58:37 +01:00
|
|
|
fail:
|
2024-04-17 09:20:29 +02:00
|
|
|
WINPR_PRAGMA_DIAG_PUSH
|
|
|
|
|
WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
|
2020-12-15 09:58:37 +01:00
|
|
|
progressive_context_free(progressive);
|
2024-04-17 09:20:29 +02:00
|
|
|
WINPR_PRAGMA_DIAG_POP
|
2026-02-26 15:06:27 +01:00
|
|
|
return nullptr;
|
2014-07-28 17:42:23 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void progressive_context_free(PROGRESSIVE_CONTEXT* progressive)
|
|
|
|
|
{
|
|
|
|
|
if (!progressive)
|
|
|
|
|
return;
|
|
|
|
|
|
2020-12-15 09:58:37 +01:00
|
|
|
Stream_Free(progressive->buffer, TRUE);
|
|
|
|
|
Stream_Free(progressive->rects, TRUE);
|
|
|
|
|
rfx_context_free(progressive->rfx_context);
|
|
|
|
|
|
2014-08-06 10:23:14 -04:00
|
|
|
BufferPool_Free(progressive->bufferPool);
|
2022-04-06 10:10:07 +02:00
|
|
|
HashTable_Free(progressive->SurfaceContexts);
|
2014-09-12 14:57:44 -04:00
|
|
|
|
2023-03-24 12:44:04 +01:00
|
|
|
winpr_aligned_free(progressive);
|
2014-07-28 17:42:23 -04:00
|
|
|
}
|