4#include <freerdp/freerdp.h>
5#include <freerdp/codec/color.h>
6#include <freerdp/codec/av2.h>
8WINPR_ATTR_MALLOC(free, 1)
9static
void* allocRGB(uint32_t format, uint32_t width, uint32_t height, uint32_t* pstride)
11 const size_t bpp = FreeRDPGetBytesPerPixel(format);
12 const size_t stride = bpp * width + 32;
13 WINPR_ASSERT(pstride);
14 *pstride = WINPR_ASSERTING_INT_CAST(uint32_t, stride);
16 if ((stride == 0) || (height == 0))
19 uint8_t* rgb = calloc(stride, height);
23 for (
size_t x = 0; x < height; x++)
25 if (winpr_RAND(&rgb[x * stride], width * bpp) < 0)
35static BOOL testEncodeDecode(uint32_t format, uint32_t width, uint32_t height)
41 FREERDP_AV2_CONTEXT* enc = freerdp_av2_context_new(TRUE);
42 FREERDP_AV2_CONTEXT* dec = freerdp_av2_context_new(FALSE);
46 if (!freerdp_av2_context_reset(enc, width, height))
48 if (!freerdp_av2_context_reset(dec, width, height))
53 src = allocRGB(format, width, height, &stride);
54 out = allocRGB(format, width, height, &ostride);
55 if (!src || !out || (stride < width) || (stride != ostride))
58 const RECTANGLE_16 rect = { .left = 0, .top = 0, .right = width, .bottom = height };
59 uint8_t* dst =
nullptr;
61 if (freerdp_av2_compress(enc, src, format, stride, width, height, &rect, &dst, &dstsize,
64 if ((dstsize == 0) || !dst)
70 rc = freerdp_av2_decompress(dec, dst, dstsize, out, format, stride, width, height, &rect, 1) >=
74 freerdp_av2_context_free(enc);
75 freerdp_av2_context_free(dec);
76 free_h264_metablock(&meta);
88static BOOL testColours(uint32_t profile, uint32_t width, uint32_t height)
90 const uint32_t format = PIXEL_FORMAT_BGRX32;
91 const uint32_t bpp = FreeRDPGetBytesPerPixel(format);
92 const uint32_t stride = width * bpp;
94 uint8_t* src = calloc(stride, height);
95 uint8_t* out = calloc(stride, height);
97 FREERDP_AV2_CONTEXT* enc = freerdp_av2_context_new(TRUE);
98 FREERDP_AV2_CONTEXT* dec = freerdp_av2_context_new(FALSE);
99 if (!src || !out || !enc || !dec)
102 if (!freerdp_av2_context_reset(enc, width, height) ||
103 !freerdp_av2_context_reset(dec, width, height))
105 if (!freerdp_av2_context_set_option(enc, FREERDP_AV2_CONTEXT_OPTION_PROFILE, profile) ||
106 !freerdp_av2_context_set_option(enc, FREERDP_AV2_CONTEXT_OPTION_RATECONTROL,
108 !freerdp_av2_context_set_option(enc, FREERDP_AV2_CONTEXT_OPTION_BITRATE, 100000))
111 for (uint32_t y = 0; y < height; y++)
113 for (uint32_t x = 0; x < width; x++)
116 (profile == 1) ? ((x % 2) == 0) && ((y % 2) == 0) : (((x / 8) + (y / 8)) % 2) == 0;
117 const uint32_t color = first ? FreeRDPGetColor(format, 0xA0, 0x60, 0x60, 0xFF)
118 : FreeRDPGetColor(format, 0x60, 0x60, 0xA0, 0xFF);
119 if (!FreeRDPWriteColor(&src[y * stride + x * bpp], format, color))
124 const RECTANGLE_16 rect = { .left = 0, .top = 0, .right = width, .bottom = height };
125 uint8_t* dst =
nullptr;
126 uint32_t dstsize = 0;
127 if (freerdp_av2_compress(enc, src, format, stride, width, height, &rect, &dst, &dstsize,
130 if (freerdp_av2_decompress(dec, dst, dstsize, out, format, stride, width, height, &rect, 1) < 0)
134 for (uint32_t y = 0; y < height; y++)
136 for (uint32_t x = 0; x < width; x++)
144 FreeRDPSplitColor(FreeRDPReadColor(&src[y * stride + x * bpp], format), format, &r1,
145 &g1, &b1,
nullptr,
nullptr);
146 FreeRDPSplitColor(FreeRDPReadColor(&out[y * stride + x * bpp], format), format, &r2,
147 &g2, &b2,
nullptr,
nullptr);
148 maxDiff = MAX(maxDiff, abs(r1 - r2));
149 maxDiff = MAX(maxDiff, abs(g1 - g2));
150 maxDiff = MAX(maxDiff, abs(b1 - b2));
154 (void)fprintf(stderr,
"[%s] %s %" PRIu32
"x%" PRIu32
": maximum colour difference %d\n",
155 __func__, (profile == 1) ?
"YUV444" :
"YUV420", width, height, maxDiff);
159 freerdp_av2_context_free(enc);
160 freerdp_av2_context_free(dec);
161 free_h264_metablock(&meta);
170static BOOL testSequence(uint32_t width, uint32_t height, uint32_t frames)
172 const uint32_t format = PIXEL_FORMAT_BGRX32;
173 const uint32_t bpp = FreeRDPGetBytesPerPixel(format);
174 const uint32_t stride = width * bpp;
176 uint8_t* src = calloc(stride, height);
177 uint8_t* out = calloc(stride, height);
178 FREERDP_AV2_CONTEXT* enc = freerdp_av2_context_new(TRUE);
179 FREERDP_AV2_CONTEXT* dec = freerdp_av2_context_new(FALSE);
180 if (!src || !out || !enc || !dec)
183 if (!freerdp_av2_context_reset(enc, width, height) ||
184 !freerdp_av2_context_reset(dec, width, height))
186 if (!freerdp_av2_context_set_option(enc, FREERDP_AV2_CONTEXT_OPTION_PROFILE, 0) ||
187 !freerdp_av2_context_set_option(enc, FREERDP_AV2_CONTEXT_OPTION_RATECONTROL,
189 !freerdp_av2_context_set_option(enc, FREERDP_AV2_CONTEXT_OPTION_BITRATE, 100000))
192 for (uint32_t f = 0; f < frames; f++)
195 for (uint32_t y = 0; y < height; y++)
197 for (uint32_t x = 0; x < width; x++)
199 const BOOL first = ((((x + 4 * f) / 8) + (y / 8)) % 2) == 0;
200 const uint32_t color = first ? FreeRDPGetColor(format, 0xA0, 0x60, 0x60, 0xFF)
201 : FreeRDPGetColor(format, 0x60, 0x60, 0xA0, 0xFF);
202 if (!FreeRDPWriteColor(&src[y * stride + x * bpp], format, color))
208 const RECTANGLE_16 rect = { .left = 0, .top = 0, .right = width, .bottom = height };
209 uint8_t* dst =
nullptr;
210 uint32_t dstsize = 0;
211 const INT32 crc = freerdp_av2_compress(enc, src, format, stride, width, height, &rect, &dst,
213 free_h264_metablock(&meta);
214 if ((crc <= 0) || !dst || (dstsize == 0))
216 if (freerdp_av2_decompress(dec, dst, dstsize, out, format, stride, width, height, &rect,
221 for (uint32_t y = 0; y < height; y++)
223 for (uint32_t x = 0; x < width; x++)
231 FreeRDPSplitColor(FreeRDPReadColor(&src[y * stride + x * bpp], format), format, &r1,
232 &g1, &b1,
nullptr,
nullptr);
233 FreeRDPSplitColor(FreeRDPReadColor(&out[y * stride + x * bpp], format), format, &r2,
234 &g2, &b2,
nullptr,
nullptr);
235 maxDiff = MAX(maxDiff, abs(r1 - r2));
236 maxDiff = MAX(maxDiff, abs(g1 - g2));
237 maxDiff = MAX(maxDiff, abs(b1 - b2));
241 (void)fprintf(stderr,
242 "[%s] frame %" PRIu32
" %" PRIu32
"x%" PRIu32
" (%" PRIu32
243 " bytes): maximum colour difference %d\n",
244 __func__, f, width, height, dstsize, maxDiff);
251 freerdp_av2_context_free(enc);
252 freerdp_av2_context_free(dec);
258int TestFreeRDPCodecAV2(
int argc,
char* argv[])
263#if !defined(WITH_LIBAVM)
264 (void)fprintf(stderr,
"[%s] skipping, no AV2 encoder support compiled in\n", __func__);
267 const UINT32 width = 124;
268 const UINT32 height = 54;
269 const UINT32 formats[] = { PIXEL_FORMAT_BGRA32, PIXEL_FORMAT_RGB16 };
271 for (
size_t x = 0; x < ARRAYSIZE(formats); x++)
273 if (!testEncodeDecode(formats[x], width, height))
277 if (!testColours(0, 64, 64))
279 if (!testColours(1, 64, 64))
281 if (!testSequence(64, 64, 4))