PR #25481 opened by Kilian (lusoris) URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25481 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25481.patch
This test-only patch addresses GCC 14.4.0 and 16.2.1 -Wstack-usage diagnostics against -Wstack-usage=122880 in 11 checkasm tests: tests/checkasm/aacpsdsp.c, tests/checkasm/mpegvideoencdsp.c, tests/checkasm/scene_sad.c, tests/checkasm/sw_gbrp.c, tests/checkasm/sw_rgb.c, tests/checkasm/sw_xyz2rgb.c, tests/checkasm/sw_yuv2rgb.c, tests/checkasm/utvideodsp.c, tests/checkasm/vc1dsp.c, tests/checkasm/vf_convolution.c and tests/checkasm/vf_eq.c. Result: warnings in these files go from 13 to 0 with GCC 14.4.0 and from 13 to 0 with GCC 16.2.1. What the patch does: - `tests/checkasm: move large scratch buffers to the heap`: moves large sample and pixel buffers, including equalizer buffers, to heap storage, asserts allocation success and frees the buffers after use. Behaviour change: test-only buffers use heap allocations with allocation assertions and cleanup; test cases and comparisons are unchanged. Base: FFmpeg master 46f23be8b1. Testing: - GCC 14.4.0 (`--enable-gpl --enable-vulkan`) and GCC 16.2.1 (`--enable-gpl --enable-vulkan --enable-vaapi --enable-libdrm --enable-nvenc`), targets all, alltools, examples, testprogs and checkasm: master 46f23be8b1 shows, with each compiler, 13 -Wstack-usage warnings in these 11 files (2 each in sw_rgb.c and utvideodsp.c, 1 in each of the others); with this patch there are none and no new ones. - FATE with GCC 16.2.1, all 102 `fate-checkasm-*` tests: all 102 ran and pass on master and with this patch. The VVC checkasm tests are covered by the separate VVC pull request. Split out of #25111 so that each part reaches the reviewers for its area. >From 2c722d123f208d82930cfa400b57f92420113160 Mon Sep 17 00:00:00 2001 From: lusoris <[email protected]> Date: Mon, 26 Oct 2026 11:24:50 +0100 Subject: [PATCH] tests/checkasm: move large scratch buffers to the heap GCC 14.4.0 and 16.2.1 report -Wstack-usage against FFmpeg's default -Wstack-usage=122880 limit in multiple checks. Large automatic sample and pixel buffers increase their stack requirements. Move those buffers, including the equalizer buffers, to heap storage, assert allocation success and free them after use. Keep the same test cases and comparisons. Signed-off-by: lusoris <[email protected]> --- tests/checkasm/aacpsdsp.c | 58 ++++++++++-------- tests/checkasm/mpegvideoencdsp.c | 22 ++++--- tests/checkasm/scene_sad.c | 17 ++++-- tests/checkasm/sw_gbrp.c | 47 +++++++++----- tests/checkasm/sw_rgb.c | 102 ++++++++++++++++++++++--------- tests/checkasm/sw_xyz2rgb.c | 35 ++++++----- tests/checkasm/sw_yuv2rgb.c | 60 +++++++++++++----- tests/checkasm/utvideodsp.c | 65 ++++++++++++-------- tests/checkasm/vc1dsp.c | 16 +++-- tests/checkasm/vf_convolution.c | 14 ++++- tests/checkasm/vf_eq.c | 14 ++++- 11 files changed, 309 insertions(+), 141 deletions(-) diff --git a/tests/checkasm/aacpsdsp.c b/tests/checkasm/aacpsdsp.c index 7388ed03efa..a293199df84 100644 --- a/tests/checkasm/aacpsdsp.c +++ b/tests/checkasm/aacpsdsp.c @@ -19,7 +19,9 @@ #include <string.h> #include "libavcodec/aacpsdsp.h" +#include "libavutil/avassert.h" #include "libavutil/intfloat.h" +#include "libavutil/mem.h" #include "libavutil/mem_internal.h" #include "checkasm.h" @@ -187,50 +189,58 @@ static void test_hybrid_synthesis_deint(void) static void test_stereo_interpolate(PSDSPContext *psdsp) { + struct StereoInterpolateBuffers { + INTFLOAT l[BUF_SIZE][2]; + INTFLOAT r[BUF_SIZE][2]; + INTFLOAT l0[BUF_SIZE][2]; + INTFLOAT r0[BUF_SIZE][2]; + INTFLOAT l1[BUF_SIZE][2]; + INTFLOAT r1[BUF_SIZE][2]; + INTFLOAT h[2][4]; + INTFLOAT h_step[2][4]; + } *buffers = av_malloc(sizeof(*buffers)); int i; - LOCAL_ALIGNED_16(INTFLOAT, l, [BUF_SIZE], [2]); - LOCAL_ALIGNED_16(INTFLOAT, r, [BUF_SIZE], [2]); - LOCAL_ALIGNED_16(INTFLOAT, l0, [BUF_SIZE], [2]); - LOCAL_ALIGNED_16(INTFLOAT, r0, [BUF_SIZE], [2]); - LOCAL_ALIGNED_16(INTFLOAT, l1, [BUF_SIZE], [2]); - LOCAL_ALIGNED_16(INTFLOAT, r1, [BUF_SIZE], [2]); - LOCAL_ALIGNED_16(INTFLOAT, h, [2], [4]); - LOCAL_ALIGNED_16(INTFLOAT, h_step, [2], [4]); declare_func(void, INTFLOAT (*l)[2], INTFLOAT (*r)[2], INTFLOAT h[2][4], INTFLOAT h_step[2][4], int len); - randomize((INTFLOAT *)l, BUF_SIZE * 2); - randomize((INTFLOAT *)r, BUF_SIZE * 2); + av_assert0(buffers); + + randomize((INTFLOAT *)buffers->l, BUF_SIZE * 2); + randomize((INTFLOAT *)buffers->r, BUF_SIZE * 2); for (i = 0; i < 2; i++) { if (check_func(psdsp->stereo_interpolate[i], "ps_stereo_interpolate%s", i ? "_ipdopd" : "")) { - memcpy(l0, l, BUF_SIZE * 2 * sizeof(INTFLOAT)); - memcpy(l1, l, BUF_SIZE * 2 * sizeof(INTFLOAT)); - memcpy(r0, r, BUF_SIZE * 2 * sizeof(INTFLOAT)); - memcpy(r1, r, BUF_SIZE * 2 * sizeof(INTFLOAT)); + memcpy(buffers->l0, buffers->l, BUF_SIZE * 2 * sizeof(INTFLOAT)); + memcpy(buffers->l1, buffers->l, BUF_SIZE * 2 * sizeof(INTFLOAT)); + memcpy(buffers->r0, buffers->r, BUF_SIZE * 2 * sizeof(INTFLOAT)); + memcpy(buffers->r1, buffers->r, BUF_SIZE * 2 * sizeof(INTFLOAT)); - randomize((INTFLOAT *)h, 2 * 4); - randomize((INTFLOAT *)h_step, 2 * 4); + randomize((INTFLOAT *)buffers->h, 2 * 4); + randomize((INTFLOAT *)buffers->h_step, 2 * 4); // Clear the least significant 14 bits of h_step, to avoid // divergence when accumulating h_step BUF_SIZE times into // a float variable which may or may not have extra intermediate // precision. Therefore clear roughly log2(BUF_SIZE) less // significant bits, to get the same result regardless of any // extra precision in the accumulator. - clear_less_significant_bits((INTFLOAT *)h_step, 2 * 4, 14); + clear_less_significant_bits((INTFLOAT *)buffers->h_step, 2 * 4, 14); - call_ref(l0, r0, h, h_step, BUF_SIZE); - call_new(l1, r1, h, h_step, BUF_SIZE); - if (!float_near_abs_eps_array((float *)l0, (float *)l1, EPS, BUF_SIZE * 2) || - !float_near_abs_eps_array((float *)r0, (float *)r1, EPS, BUF_SIZE * 2)) + call_ref(buffers->l0, buffers->r0, buffers->h, buffers->h_step, BUF_SIZE); + call_new(buffers->l1, buffers->r1, buffers->h, buffers->h_step, BUF_SIZE); + if (!float_near_abs_eps_array((float *)buffers->l0, (float *)buffers->l1, + EPS, BUF_SIZE * 2) || + !float_near_abs_eps_array((float *)buffers->r0, (float *)buffers->r1, + EPS, BUF_SIZE * 2)) fail(); - memcpy(l1, l, BUF_SIZE * 2 * sizeof(INTFLOAT)); - memcpy(r1, r, BUF_SIZE * 2 * sizeof(INTFLOAT)); - bench_new(l1, r1, h, h_step, BUF_SIZE); + memcpy(buffers->l1, buffers->l, BUF_SIZE * 2 * sizeof(INTFLOAT)); + memcpy(buffers->r1, buffers->r, BUF_SIZE * 2 * sizeof(INTFLOAT)); + bench_new(buffers->l1, buffers->r1, buffers->h, buffers->h_step, BUF_SIZE); } } + + av_free(buffers); } void checkasm_check_aacpsdsp(void) diff --git a/tests/checkasm/mpegvideoencdsp.c b/tests/checkasm/mpegvideoencdsp.c index 5fad1d4bb4b..c4456bf70a8 100644 --- a/tests/checkasm/mpegvideoencdsp.c +++ b/tests/checkasm/mpegvideoencdsp.c @@ -16,8 +16,10 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/avassert.h" #include "libavutil/common.h" #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "libavutil/mem_internal.h" #include "libavcodec/mathops.h" @@ -144,12 +146,16 @@ static void check_pix_norm1(MpegvideoEncDSPContext *c) static void check_draw_edges(MpegvideoEncDSPContext *c) { static const int input_sizes[] = {8, 128, 1080, MAX_LINE_SIZE, -MAX_LINE_SIZE}; - LOCAL_ALIGNED_16(uint8_t, buf0, [BUFSIZE]); - LOCAL_ALIGNED_16(uint8_t, buf1, [BUFSIZE]); + struct DrawEdgesBuffers { + uint8_t buf0[BUFSIZE]; + uint8_t buf1[BUFSIZE]; + } *buffers = av_malloc(sizeof(*buffers)); declare_func(void, uint8_t *buf, ptrdiff_t wrap, int width, int height, int w, int h, int sides); + av_assert0(buffers); + for (int isi = 0; isi < FF_ARRAY_ELEMS(input_sizes); isi++) { int input_size = input_sizes[isi]; int negstride = input_size < 0; @@ -158,8 +164,8 @@ static void check_draw_edges(MpegvideoEncDSPContext *c) ptrdiff_t linesize = EDGE_WIDTH + width + EDGE_WIDTH; /* calculate height based on specified width to use the entire buffer. */ int height = (BUFSIZE / linesize) - (2 * EDGE_WIDTH); - uint8_t *dst0 = buf0 + EDGE_WIDTH * linesize + EDGE_WIDTH; - uint8_t *dst1 = buf1 + EDGE_WIDTH * linesize + EDGE_WIDTH; + uint8_t *dst0 = buffers->buf0 + EDGE_WIDTH * linesize + EDGE_WIDTH; + uint8_t *dst1 = buffers->buf1 + EDGE_WIDTH * linesize + EDGE_WIDTH; if (negstride) { dst0 += (height - 1) * linesize; @@ -170,16 +176,18 @@ static void check_draw_edges(MpegvideoEncDSPContext *c) for (int shift = 0; shift < 3; shift++) { int edge = EDGE_WIDTH >> shift; if (check_func(c->draw_edges, "draw_edges_%d_%d_%d%s", width, height, edge, negstride_str)) { - randomize_buffers(buf0, BUFSIZE); - memcpy(buf1, buf0, BUFSIZE); + randomize_buffers(buffers->buf0, BUFSIZE); + memcpy(buffers->buf1, buffers->buf0, BUFSIZE); call_ref(dst0, linesize, width, height, edge, edge, EDGE_BOTTOM | EDGE_TOP); call_new(dst1, linesize, width, height, edge, edge, EDGE_BOTTOM | EDGE_TOP); - if (memcmp(buf0, buf1, BUFSIZE)) + if (memcmp(buffers->buf0, buffers->buf1, BUFSIZE)) fail(); bench_new(dst1, linesize, width, height, edge, edge, EDGE_BOTTOM | EDGE_TOP); } } } + + av_free(buffers); } #undef NUM_LINES diff --git a/tests/checkasm/scene_sad.c b/tests/checkasm/scene_sad.c index bc33c428c63..93505de3820 100644 --- a/tests/checkasm/scene_sad.c +++ b/tests/checkasm/scene_sad.c @@ -18,6 +18,8 @@ #include "checkasm.h" #include "libavfilter/scene_sad.h" +#include "libavutil/avassert.h" +#include "libavutil/mem.h" #include "libavutil/mem_internal.h" #define WIDTH 256 @@ -32,10 +34,8 @@ tmp_buf[j] = rnd() & mask; \ } while (0) -static void check_scene_sad(int depth) +static void check_scene_sad(int depth, uint8_t *src1, uint8_t *src2) { - LOCAL_ALIGNED_32(uint8_t, src1, [WIDTH * HEIGHT * 2]); - LOCAL_ALIGNED_32(uint8_t, src2, [WIDTH * HEIGHT * 2]); declare_func(void, const uint8_t *src1, ptrdiff_t stride1, const uint8_t *src2, ptrdiff_t stride2, ptrdiff_t width, ptrdiff_t height, uint64_t *sum); @@ -66,8 +66,17 @@ static void check_scene_sad(int depth) void checkasm_check_scene_sad(void) { const int depths[] = { 8, 10, 12, 14, 15, 16 }; + uint8_t *buffers = av_malloc(2 * WIDTH * HEIGHT * 2); + uint8_t *src1 = buffers; + uint8_t *src2; + + av_assert0(buffers); + src2 = buffers + WIDTH * HEIGHT * 2; + for (int i = 0; i < FF_ARRAY_ELEMS(depths); i++) { - check_scene_sad(depths[i]); + check_scene_sad(depths[i], src1, src2); report("scene_sad%d", depths[i]); } + + av_free(buffers); } diff --git a/tests/checkasm/sw_gbrp.c b/tests/checkasm/sw_gbrp.c index 4fcb87cd5f2..2b5748a52a0 100644 --- a/tests/checkasm/sw_gbrp.c +++ b/tests/checkasm/sw_gbrp.c @@ -19,8 +19,10 @@ #include <string.h> +#include "libavutil/avassert.h" #include "libavutil/common.h" #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "libavutil/mem_internal.h" #include "libavutil/pixdesc.h" @@ -75,6 +77,23 @@ static void check_output_yuv2gbrp(void) static const int input_sizes[] = {8, 24, 128, 144, 256, 512}; uint8_t *dst0[4]; uint8_t *dst1[4]; + int32_t *src_y, *src_u, *src_v, *src_a; + uint8_t *dst0_r, *dst0_g, *dst0_b, *dst0_a; + uint8_t *dst1_r, *dst1_g, *dst1_b, *dst1_a; + struct OutputYuv2GbrpBuffers { + int32_t src_y[LARGEST_FILTER * LARGEST_INPUT_SIZE]; + int32_t src_u[LARGEST_FILTER * LARGEST_INPUT_SIZE]; + int32_t src_v[LARGEST_FILTER * LARGEST_INPUT_SIZE]; + int32_t src_a[LARGEST_FILTER * LARGEST_INPUT_SIZE]; + uint8_t dst0_r[LARGEST_INPUT_SIZE * sizeof(int32_t)]; + uint8_t dst0_g[LARGEST_INPUT_SIZE * sizeof(int32_t)]; + uint8_t dst0_b[LARGEST_INPUT_SIZE * sizeof(int32_t)]; + uint8_t dst0_a[LARGEST_INPUT_SIZE * sizeof(int32_t)]; + uint8_t dst1_r[LARGEST_INPUT_SIZE * sizeof(int32_t)]; + uint8_t dst1_g[LARGEST_INPUT_SIZE * sizeof(int32_t)]; + uint8_t dst1_b[LARGEST_INPUT_SIZE * sizeof(int32_t)]; + uint8_t dst1_a[LARGEST_INPUT_SIZE * sizeof(int32_t)]; + } *buffers = av_malloc(sizeof(*buffers)); declare_func(void, SwsInternal *c, const int16_t *lumFilter, const int16_t **lumSrcx, int lumFilterSize, @@ -91,20 +110,19 @@ static void check_output_yuv2gbrp(void) LOCAL_ALIGNED_8(int16_t, luma_filter, [LARGEST_FILTER]); LOCAL_ALIGNED_8(int16_t, chr_filter, [LARGEST_FILTER]); - LOCAL_ALIGNED_8(int32_t, src_y, [LARGEST_FILTER * LARGEST_INPUT_SIZE]); - LOCAL_ALIGNED_8(int32_t, src_u, [LARGEST_FILTER * LARGEST_INPUT_SIZE]); - LOCAL_ALIGNED_8(int32_t, src_v, [LARGEST_FILTER * LARGEST_INPUT_SIZE]); - LOCAL_ALIGNED_8(int32_t, src_a, [LARGEST_FILTER * LARGEST_INPUT_SIZE]); - - LOCAL_ALIGNED_8(uint8_t, dst0_r, [LARGEST_INPUT_SIZE * sizeof(int32_t)]); - LOCAL_ALIGNED_8(uint8_t, dst0_g, [LARGEST_INPUT_SIZE * sizeof(int32_t)]); - LOCAL_ALIGNED_8(uint8_t, dst0_b, [LARGEST_INPUT_SIZE * sizeof(int32_t)]); - LOCAL_ALIGNED_8(uint8_t, dst0_a, [LARGEST_INPUT_SIZE * sizeof(int32_t)]); - - LOCAL_ALIGNED_8(uint8_t, dst1_r, [LARGEST_INPUT_SIZE * sizeof(int32_t)]); - LOCAL_ALIGNED_8(uint8_t, dst1_g, [LARGEST_INPUT_SIZE * sizeof(int32_t)]); - LOCAL_ALIGNED_8(uint8_t, dst1_b, [LARGEST_INPUT_SIZE * sizeof(int32_t)]); - LOCAL_ALIGNED_8(uint8_t, dst1_a, [LARGEST_INPUT_SIZE * sizeof(int32_t)]); + av_assert0(buffers); + src_y = buffers->src_y; + src_u = buffers->src_u; + src_v = buffers->src_v; + src_a = buffers->src_a; + dst0_r = buffers->dst0_r; + dst0_g = buffers->dst0_g; + dst0_b = buffers->dst0_b; + dst0_a = buffers->dst0_a; + dst1_r = buffers->dst1_r; + dst1_g = buffers->dst1_g; + dst1_b = buffers->dst1_b; + dst1_a = buffers->dst1_a; randomize_buffers((uint8_t*)src_y, LARGEST_FILTER * LARGEST_INPUT_SIZE * sizeof(int32_t)); randomize_buffers((uint8_t*)src_u, LARGEST_FILTER * LARGEST_INPUT_SIZE * sizeof(int32_t)); @@ -183,6 +201,7 @@ static void check_output_yuv2gbrp(void) } } sws_freeContext(sws); + av_free(buffers); } #undef LARGEST_INPUT_SIZE diff --git a/tests/checkasm/sw_rgb.c b/tests/checkasm/sw_rgb.c index 723f8104113..041165c5eda 100644 --- a/tests/checkasm/sw_rgb.c +++ b/tests/checkasm/sw_rgb.c @@ -19,8 +19,10 @@ #include <string.h> +#include "libavutil/avassert.h" #include "libavutil/common.h" #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "libavutil/mem_internal.h" #include "libavutil/pixdesc.h" @@ -75,21 +77,36 @@ static void check_shuffle_bytes(void * func, const char * report) static void check_interleaved_to_planar(void *func, const char *report, int odd_tail) { + struct UyvyTo422pBuffers { + uint8_t src0[MAX_STRIDE * MAX_HEIGHT * 2]; + uint8_t src1[MAX_STRIDE * MAX_HEIGHT * 2]; + uint8_t dst_y_0[MAX_STRIDE * MAX_HEIGHT]; + uint8_t dst_y_1[MAX_STRIDE * MAX_HEIGHT]; + uint8_t dst_u_0[(MAX_STRIDE / 2) * MAX_HEIGHT]; + uint8_t dst_u_1[(MAX_STRIDE / 2) * MAX_HEIGHT]; + uint8_t dst_v_0[(MAX_STRIDE / 2) * MAX_HEIGHT]; + uint8_t dst_v_1[(MAX_STRIDE / 2) * MAX_HEIGHT]; + } *buffers = av_malloc(sizeof(*buffers)); + uint8_t *src0, *src1; + uint8_t *dst_y_0, *dst_y_1; + uint8_t *dst_u_0, *dst_u_1; + uint8_t *dst_v_0, *dst_v_1; int i; - LOCAL_ALIGNED_32(uint8_t, src0, [MAX_STRIDE * MAX_HEIGHT * 2]); - LOCAL_ALIGNED_32(uint8_t, src1, [MAX_STRIDE * MAX_HEIGHT * 2]); - LOCAL_ALIGNED_32(uint8_t, dst_y_0, [MAX_STRIDE * MAX_HEIGHT]); - LOCAL_ALIGNED_32(uint8_t, dst_y_1, [MAX_STRIDE * MAX_HEIGHT]); - LOCAL_ALIGNED_32(uint8_t, dst_u_0, [(MAX_STRIDE/2) * MAX_HEIGHT]); - LOCAL_ALIGNED_32(uint8_t, dst_u_1, [(MAX_STRIDE/2) * MAX_HEIGHT]); - LOCAL_ALIGNED_32(uint8_t, dst_v_0, [(MAX_STRIDE/2) * MAX_HEIGHT]); - LOCAL_ALIGNED_32(uint8_t, dst_v_1, [(MAX_STRIDE/2) * MAX_HEIGHT]); - declare_func(void, uint8_t *ydst, uint8_t *udst, uint8_t *vdst, const uint8_t *src, int width, int height, int lumStride, int chromStride, int srcStride); + av_assert0(buffers); + src0 = buffers->src0; + src1 = buffers->src1; + dst_y_0 = buffers->dst_y_0; + dst_y_1 = buffers->dst_y_1; + dst_u_0 = buffers->dst_u_0; + dst_u_1 = buffers->dst_u_1; + dst_v_0 = buffers->dst_v_0; + dst_v_1 = buffers->dst_v_1; + randomize_buffers(src0, MAX_STRIDE * MAX_HEIGHT * 2); memcpy(src1, src0, MAX_STRIDE * MAX_HEIGHT * 2); @@ -117,6 +134,8 @@ static void check_interleaved_to_planar(void *func, const char *report, int odd_ bench_new(dst_y_1, dst_u_1, dst_v_1, src1, planes[5].w, planes[5].h, MAX_STRIDE, MAX_STRIDE / 2, 2 * planes[5].w); } + + av_free(buffers); } #define NUM_LINES 5 @@ -717,17 +736,27 @@ static void check_yuv2packedX(void) const int16_t *chru[LARGEST_FILTER]; const int16_t *chrv[LARGEST_FILTER]; const int16_t *alpha[LARGEST_FILTER]; + int32_t *src_y, *src_u, *src_v, *src_a; + uint8_t *dst0, *dst1; + struct Yuv2PackedXBuffers { + int32_t src_y[LARGEST_FILTER * INPUT_SIZE]; + int32_t src_u[LARGEST_FILTER * INPUT_SIZE]; + int32_t src_v[LARGEST_FILTER * INPUT_SIZE]; + int32_t src_a[LARGEST_FILTER * INPUT_SIZE]; + uint8_t dst0[INPUT_SIZE * sizeof(int32_t[4])]; + uint8_t dst1[INPUT_SIZE * sizeof(int32_t[4])]; + } *buffers = av_malloc(sizeof(*buffers)); LOCAL_ALIGNED_8(int16_t, luma_filter, [LARGEST_FILTER]); LOCAL_ALIGNED_8(int16_t, chr_filter, [LARGEST_FILTER]); - LOCAL_ALIGNED_8(int32_t, src_y, [LARGEST_FILTER * INPUT_SIZE]); - LOCAL_ALIGNED_8(int32_t, src_u, [LARGEST_FILTER * INPUT_SIZE]); - LOCAL_ALIGNED_8(int32_t, src_v, [LARGEST_FILTER * INPUT_SIZE]); - LOCAL_ALIGNED_8(int32_t, src_a, [LARGEST_FILTER * INPUT_SIZE]); - - LOCAL_ALIGNED_8(uint8_t, dst0, [INPUT_SIZE * sizeof(int32_t[4])]); - LOCAL_ALIGNED_8(uint8_t, dst1, [INPUT_SIZE * sizeof(int32_t[4])]); + av_assert0(buffers); + src_y = buffers->src_y; + src_u = buffers->src_u; + src_v = buffers->src_v; + src_a = buffers->src_a; + dst0 = buffers->dst0; + dst1 = buffers->dst1; randomize_buffers((uint8_t*)src_y, LARGEST_FILTER * INPUT_SIZE * sizeof(int32_t)); randomize_buffers((uint8_t*)src_u, LARGEST_FILTER * INPUT_SIZE * sizeof(int32_t)); @@ -801,6 +830,8 @@ static void check_yuv2packedX(void) sws_freeContext(sws); } + + av_free(buffers); } #undef INPUT_SIZE @@ -809,6 +840,18 @@ static void check_yuv2packedX(void) void checkasm_check_sw_rgb(void) { SwsContext *sws; +#define RGB_CONVERSION_BUF_SIZE FFALIGN(MAX_LINE_SIZE * 4 + 8, 32) + uint8_t *conversion_buffers = av_malloc(4 * RGB_CONVERSION_BUF_SIZE); + uint8_t *conversion_src0; + uint8_t *conversion_src1; + uint8_t *conversion_dst0; + uint8_t *conversion_dst1; + + av_assert0(conversion_buffers); + conversion_src0 = conversion_buffers; + conversion_src1 = conversion_src0 + RGB_CONVERSION_BUF_SIZE; + conversion_dst0 = conversion_src1 + RGB_CONVERSION_BUF_SIZE; + conversion_dst1 = conversion_dst0 + RGB_CONVERSION_BUF_SIZE; ff_sws_rgb2rgb_init(); @@ -845,10 +888,10 @@ void checkasm_check_sw_rgb(void) static const int rgb24_width[] = {3, 12, 24, 36, 48, 126, 1920 * 3}; int i; #define RGB24_BENCH_WIDTH (1920 * 3) - LOCAL_ALIGNED_32(uint8_t, src0, [RGB24_BENCH_WIDTH]); - LOCAL_ALIGNED_32(uint8_t, src1, [RGB24_BENCH_WIDTH]); - LOCAL_ALIGNED_32(uint8_t, dst0, [RGB24_BENCH_WIDTH]); - LOCAL_ALIGNED_32(uint8_t, dst1, [RGB24_BENCH_WIDTH]); + uint8_t *src0 = conversion_src0; + uint8_t *src1 = conversion_src1; + uint8_t *dst0 = conversion_dst0; + uint8_t *dst1 = conversion_dst1; declare_func(void, const uint8_t *src, uint8_t *dst, int src_size); @@ -887,10 +930,10 @@ void checkasm_check_sw_rgb(void) static const int rgb32_widths[] = {4, 16, 32, 48, 64, 68, 100, 128, 1920 * 4}; #define RGB32_BENCH_WIDTH (1920 * 4) #define RGB32_DST_SIZE (RGB32_BENCH_WIDTH * 3 / 4 + 8) - LOCAL_ALIGNED_32(uint8_t, src0, [RGB32_BENCH_WIDTH]); - LOCAL_ALIGNED_32(uint8_t, src1, [RGB32_BENCH_WIDTH]); - LOCAL_ALIGNED_32(uint8_t, dst0, [RGB32_DST_SIZE]); - LOCAL_ALIGNED_32(uint8_t, dst1, [RGB32_DST_SIZE]); + uint8_t *src0 = conversion_src0; + uint8_t *src1 = conversion_src1; + uint8_t *dst0 = conversion_dst0; + uint8_t *dst1 = conversion_dst1; declare_func(void, const uint8_t *src, uint8_t *dst, int src_size); @@ -932,10 +975,10 @@ void checkasm_check_sw_rgb(void) static const int rgb24to32_widths[] = {3, 12, 24, 36, 48, 51, 126, 1920 * 3}; #define RGB24TO32_BENCH_WIDTH (1920 * 3) #define RGB24TO32_DST_SIZE (RGB24TO32_BENCH_WIDTH * 4 / 3 + 8) - LOCAL_ALIGNED_32(uint8_t, src0, [RGB24TO32_BENCH_WIDTH]); - LOCAL_ALIGNED_32(uint8_t, src1, [RGB24TO32_BENCH_WIDTH]); - LOCAL_ALIGNED_32(uint8_t, dst0, [RGB24TO32_DST_SIZE]); - LOCAL_ALIGNED_32(uint8_t, dst1, [RGB24TO32_DST_SIZE]); + uint8_t *src0 = conversion_src0; + uint8_t *src1 = conversion_src1; + uint8_t *dst0 = conversion_dst0; + uint8_t *dst1 = conversion_dst1; declare_func(void, const uint8_t *src, uint8_t *dst, int src_size); @@ -1004,4 +1047,7 @@ void checkasm_check_sw_rgb(void) check_yuv2packedX(); report("yuv2packedX"); + + av_free(conversion_buffers); +#undef RGB_CONVERSION_BUF_SIZE } diff --git a/tests/checkasm/sw_xyz2rgb.c b/tests/checkasm/sw_xyz2rgb.c index 17c5fcce7b4..f939a62d990 100644 --- a/tests/checkasm/sw_xyz2rgb.c +++ b/tests/checkasm/sw_xyz2rgb.c @@ -20,7 +20,9 @@ #include <string.h> +#include "libavutil/avassert.h" #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "libavutil/mem_internal.h" #include "libavutil/pixdesc.h" #include "libavutil/pixfmt.h" @@ -53,21 +55,23 @@ static void check_xyz12Torgb48le(void) const AVPixFmtDescriptor *src_desc = av_pix_fmt_desc_get(src_pix_fmt); const AVPixFmtDescriptor *dst_desc = av_pix_fmt_desc_get(dst_pix_fmt); - - LOCAL_ALIGNED_8(uint16_t, src, [3 * MAX_LINE_SIZE * NUM_LINES]); - LOCAL_ALIGNED_8(uint16_t, dst_ref, [3 * MAX_LINE_SIZE * NUM_LINES]); - LOCAL_ALIGNED_8(uint16_t, dst_new, [3 * MAX_LINE_SIZE * NUM_LINES]); + struct Xyz12ToRgb48Buffers { + uint16_t src[3 * MAX_LINE_SIZE * NUM_LINES]; + uint16_t dst_ref[3 * MAX_LINE_SIZE * NUM_LINES]; + uint16_t dst_new[3 * MAX_LINE_SIZE * NUM_LINES]; + } *buffers = av_malloc(sizeof(*buffers)); declare_func(void, const SwsInternal *, uint8_t *, int, const uint8_t *, int, int, int); SwsInternal c; + av_assert0(buffers); memset(&c, 0, sizeof(c)); c.opts.src_format = src_pix_fmt; ff_sws_init_xyzdsp(&c); ff_sws_fill_xyztables(&c); - randomize_buffers(src, 3 * MAX_LINE_SIZE * NUM_LINES); + randomize_buffers(buffers->src, 3 * MAX_LINE_SIZE * NUM_LINES); for (int height = 1; height <= NUM_LINES; height++) { for (int isi = 0; isi < FF_ARRAY_ELEMS(input_sizes); isi++) { @@ -75,27 +79,30 @@ static void check_xyz12Torgb48le(void) if (check_func(c.xyz12Torgb48, "%s_%s_%dx%d", src_desc->name, dst_desc->name, width, height)) { - memset(dst_ref, 0xFE, + memset(buffers->dst_ref, 0xFE, 3 * sizeof(uint16_t) * MAX_LINE_SIZE * NUM_LINES); - memset(dst_new, 0xFE, + memset(buffers->dst_new, 0xFE, 3 * sizeof(uint16_t) * MAX_LINE_SIZE * NUM_LINES); - call_ref(&c, (uint8_t *)dst_ref, dst_stride, - (const uint8_t *)src, src_stride, width, height); - call_new(&c, (uint8_t *)dst_new, dst_stride, - (const uint8_t *)src, src_stride, width, height); + call_ref(&c, (uint8_t *)buffers->dst_ref, dst_stride, + (const uint8_t *)buffers->src, src_stride, width, height); + call_new(&c, (uint8_t *)buffers->dst_new, dst_stride, + (const uint8_t *)buffers->src, src_stride, width, height); - checkasm_check(uint16_t, dst_ref, dst_stride, dst_new, + checkasm_check(uint16_t, buffers->dst_ref, dst_stride, + buffers->dst_new, dst_stride, width, height, "dst_rgb"); if (!(width & 3) && height == NUM_LINES) { - bench_new(&c, (uint8_t *)dst_new, - dst_stride, (const uint8_t *)src, src_stride, + bench_new(&c, (uint8_t *)buffers->dst_new, + dst_stride, (const uint8_t *)buffers->src, src_stride, width, height); } } } } + + av_free(buffers); } #undef NUM_LINES diff --git a/tests/checkasm/sw_yuv2rgb.c b/tests/checkasm/sw_yuv2rgb.c index 0f59d09c80e..7c1b9b18c8e 100644 --- a/tests/checkasm/sw_yuv2rgb.c +++ b/tests/checkasm/sw_yuv2rgb.c @@ -18,9 +18,11 @@ #include <string.h> +#include "libavutil/avassert.h" #include "libavutil/common.h" #include "libavutil/imgutils.h" #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "libavutil/mem_internal.h" #include "libavutil/pixdesc.h" @@ -116,22 +118,48 @@ static void check_yuv2rgb(int src_pix_fmt) declare_func(int, SwsInternal *c, const uint8_t *const src[], const int srcStride[], int srcSliceY, int srcSliceH, uint8_t *const dst[], const int dstStride[]); + struct Yuv2RgbBuffers { + uint8_t src_y[(MAX_LINE_SIZE + SRC_STRIDE_PAD) * NUM_LINES]; + uint8_t src_u[(MAX_LINE_SIZE + SRC_STRIDE_PAD) * NUM_LINES]; + uint8_t src_v[(MAX_LINE_SIZE + SRC_STRIDE_PAD) * NUM_LINES]; + uint8_t src_a[(MAX_LINE_SIZE + SRC_STRIDE_PAD) * NUM_LINES]; + uint8_t dst0_0[NUM_LINES * MAX_LINE_SIZE * 6]; + uint8_t dst0_1[NUM_LINES * MAX_LINE_SIZE]; + uint8_t dst0_2[NUM_LINES * MAX_LINE_SIZE]; + uint8_t dst1_0[NUM_LINES * MAX_LINE_SIZE * 6]; + uint8_t dst1_1[NUM_LINES * MAX_LINE_SIZE]; + uint8_t dst1_2[NUM_LINES * MAX_LINE_SIZE]; + } *buffers = av_malloc(sizeof(*buffers)); + uint8_t *src_y, *src_u, *src_v, *src_a; + uint8_t *dst0_0, *dst0_1, *dst0_2; + uint8_t *dst1_0, *dst1_1, *dst1_2; + const uint8_t *src[4]; + uint8_t *dst0[4]; + uint8_t *dst1[4]; - LOCAL_ALIGNED_8(uint8_t, src_y, [(MAX_LINE_SIZE + SRC_STRIDE_PAD) * NUM_LINES]); - LOCAL_ALIGNED_8(uint8_t, src_u, [(MAX_LINE_SIZE + SRC_STRIDE_PAD) * NUM_LINES]); - LOCAL_ALIGNED_8(uint8_t, src_v, [(MAX_LINE_SIZE + SRC_STRIDE_PAD) * NUM_LINES]); - LOCAL_ALIGNED_8(uint8_t, src_a, [(MAX_LINE_SIZE + SRC_STRIDE_PAD) * NUM_LINES]); - const uint8_t *src[4] = { src_y, src_u, src_v, src_a }; - - LOCAL_ALIGNED_8(uint8_t, dst0_0, [NUM_LINES * MAX_LINE_SIZE * 6]); - LOCAL_ALIGNED_8(uint8_t, dst0_1, [NUM_LINES * MAX_LINE_SIZE]); - LOCAL_ALIGNED_8(uint8_t, dst0_2, [NUM_LINES * MAX_LINE_SIZE]); - uint8_t *dst0[4] = { dst0_0, dst0_1, dst0_2 }; - - LOCAL_ALIGNED_8(uint8_t, dst1_0, [NUM_LINES * MAX_LINE_SIZE * 6]); - LOCAL_ALIGNED_8(uint8_t, dst1_1, [NUM_LINES * MAX_LINE_SIZE]); - LOCAL_ALIGNED_8(uint8_t, dst1_2, [NUM_LINES * MAX_LINE_SIZE]); - uint8_t *dst1[4] = { dst1_0, dst1_1, dst1_2 }; + av_assert0(buffers); + src_y = buffers->src_y; + src_u = buffers->src_u; + src_v = buffers->src_v; + src_a = buffers->src_a; + dst0_0 = buffers->dst0_0; + dst0_1 = buffers->dst0_1; + dst0_2 = buffers->dst0_2; + dst1_0 = buffers->dst1_0; + dst1_1 = buffers->dst1_1; + dst1_2 = buffers->dst1_2; + src[0] = src_y; + src[1] = src_u; + src[2] = src_v; + src[3] = src_a; + dst0[0] = dst0_0; + dst0[1] = dst0_1; + dst0[2] = dst0_2; + dst0[3] = NULL; + dst1[0] = dst1_0; + dst1[1] = dst1_1; + dst1[2] = dst1_2; + dst1[3] = NULL; randomize_buffers(src_y, (MAX_LINE_SIZE + SRC_STRIDE_PAD) * NUM_LINES); randomize_buffers(src_u, (MAX_LINE_SIZE + SRC_STRIDE_PAD) * NUM_LINES); @@ -242,6 +270,8 @@ static void check_yuv2rgb(int src_pix_fmt) sws_freeContext(sws); } } + + av_free(buffers); } #undef NUM_LINES diff --git a/tests/checkasm/utvideodsp.c b/tests/checkasm/utvideodsp.c index 2463c96603c..8a0d157c22f 100644 --- a/tests/checkasm/utvideodsp.c +++ b/tests/checkasm/utvideodsp.c @@ -22,7 +22,9 @@ #include "checkasm.h" #include "libavcodec/utvideodsp.h" +#include "libavutil/avassert.h" #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "libavutil/mem_internal.h" #define WIDTH 240 @@ -53,31 +55,44 @@ } while (0) -#define CHECK_RESTORE(type)\ -LOCAL_ALIGNED_32(type, src_r0, [BUFFER_SIZE]); \ -LOCAL_ALIGNED_32(type, src_g0, [BUFFER_SIZE]); \ -LOCAL_ALIGNED_32(type, src_b0, [BUFFER_SIZE]); \ -LOCAL_ALIGNED_32(type, src_r1, [BUFFER_SIZE]); \ -LOCAL_ALIGNED_32(type, src_g1, [BUFFER_SIZE]); \ -LOCAL_ALIGNED_32(type, src_b1, [BUFFER_SIZE]); \ -declare_func(void, type *src_r, type *src_g, type *src_b, \ - ptrdiff_t linesize_r, ptrdiff_t linesize_g, \ - ptrdiff_t linesize_b, int width, int height); \ -memset(src_r0, 0, BUFFER_SIZE * sizeof(type)); \ -memset(src_g0, 0, BUFFER_SIZE * sizeof(type)); \ -memset(src_b0, 0, BUFFER_SIZE * sizeof(type)); \ -randomize_plane(src_r0, type); \ -randomize_plane(src_g0, type); \ -randomize_plane(src_b0, type); \ -memcpy(src_r1, src_r0, BUFFER_SIZE * sizeof(type)); \ -memcpy(src_g1, src_g0, BUFFER_SIZE * sizeof(type)); \ -memcpy(src_b1, src_b0, BUFFER_SIZE * sizeof(type)); \ -call_ref(src_r0, src_g0, src_b0, WIDTH_PADDED, WIDTH_PADDED, WIDTH_PADDED, WIDTH, HEIGHT);\ -call_new(src_r1, src_g1, src_b1, WIDTH_PADDED, WIDTH_PADDED, WIDTH_PADDED, WIDTH, HEIGHT);\ -cmp_plane(src_r0, src_r1, sizeof(type)); \ -cmp_plane(src_g0, src_g1, sizeof(type)); \ -cmp_plane(src_b0, src_b1, sizeof(type)); \ -bench_new(src_r1, src_g1, src_b1, WIDTH_PADDED, WIDTH_PADDED, WIDTH_PADDED, WIDTH, HEIGHT) +#define CHECK_RESTORE(type) do { \ + type *buffers = av_malloc_array(6 * BUFFER_SIZE, sizeof(*buffers)); \ + type *src_r0; \ + type *src_g0; \ + type *src_b0; \ + type *src_r1; \ + type *src_g1; \ + type *src_b1; \ + declare_func(void, type *src_r, type *src_g, type *src_b, \ + ptrdiff_t linesize_r, ptrdiff_t linesize_g, \ + ptrdiff_t linesize_b, int width, int height); \ + av_assert0(buffers); \ + src_r0 = buffers; \ + src_g0 = src_r0 + BUFFER_SIZE; \ + src_b0 = src_g0 + BUFFER_SIZE; \ + src_r1 = src_b0 + BUFFER_SIZE; \ + src_g1 = src_r1 + BUFFER_SIZE; \ + src_b1 = src_g1 + BUFFER_SIZE; \ + memset(src_r0, 0, BUFFER_SIZE * sizeof(type)); \ + memset(src_g0, 0, BUFFER_SIZE * sizeof(type)); \ + memset(src_b0, 0, BUFFER_SIZE * sizeof(type)); \ + randomize_plane(src_r0, type); \ + randomize_plane(src_g0, type); \ + randomize_plane(src_b0, type); \ + memcpy(src_r1, src_r0, BUFFER_SIZE * sizeof(type)); \ + memcpy(src_g1, src_g0, BUFFER_SIZE * sizeof(type)); \ + memcpy(src_b1, src_b0, BUFFER_SIZE * sizeof(type)); \ + call_ref(src_r0, src_g0, src_b0, WIDTH_PADDED, WIDTH_PADDED, \ + WIDTH_PADDED, WIDTH, HEIGHT); \ + call_new(src_r1, src_g1, src_b1, WIDTH_PADDED, WIDTH_PADDED, \ + WIDTH_PADDED, WIDTH, HEIGHT); \ + cmp_plane(src_r0, src_r1, sizeof(type)); \ + cmp_plane(src_g0, src_g1, sizeof(type)); \ + cmp_plane(src_b0, src_b1, sizeof(type)); \ + bench_new(src_r1, src_g1, src_b1, WIDTH_PADDED, WIDTH_PADDED, \ + WIDTH_PADDED, WIDTH, HEIGHT); \ + av_free(buffers); \ +} while (0) static void check_restore_rgb_planes(void) { CHECK_RESTORE(uint8_t); diff --git a/tests/checkasm/vc1dsp.c b/tests/checkasm/vc1dsp.c index 52049a4aa35..85251cf34f2 100644 --- a/tests/checkasm/vc1dsp.c +++ b/tests/checkasm/vc1dsp.c @@ -24,6 +24,7 @@ #include "libavcodec/vc1dsp.h" +#include "libavutil/avassert.h" #include "libavutil/common.h" #include "libavutil/internal.h" #include "libavutil/intreadwrite.h" @@ -394,13 +395,15 @@ static void check_unescape(void) /* This appears to be a typical length of buffer in use */ #define LOG2_UNESCAPE_BUF_SIZE 17 #define UNESCAPE_BUF_SIZE (1u<<LOG2_UNESCAPE_BUF_SIZE) - LOCAL_ALIGNED_8(uint8_t, escaped0, [UNESCAPE_BUF_SIZE]); - LOCAL_ALIGNED_8(uint8_t, escaped1, [UNESCAPE_BUF_SIZE]); - LOCAL_ALIGNED_8(uint8_t, unescaped0, [UNESCAPE_BUF_SIZE]); - LOCAL_ALIGNED_8(uint8_t, unescaped1, [UNESCAPE_BUF_SIZE]); + uint8_t *escaped0 = av_malloc(UNESCAPE_BUF_SIZE); + uint8_t *escaped1 = av_malloc(UNESCAPE_BUF_SIZE); + uint8_t *unescaped0 = av_malloc(UNESCAPE_BUF_SIZE); + uint8_t *unescaped1 = av_malloc(UNESCAPE_BUF_SIZE); VC1DSPContext h; + av_assert0(escaped0 && escaped1 && unescaped0 && unescaped1); + ff_vc1dsp_init(&h); if (check_func(h.vc1_unescape_buffer, "vc1dsp.vc1_unescape_buffer")) { @@ -437,6 +440,11 @@ static void check_unescape(void) /* Benchmark the no-escape-sequences case */ bench_new(escaped1, UNESCAPE_BUF_SIZE, unescaped1); } + + av_free(escaped0); + av_free(escaped1); + av_free(unescaped0); + av_free(unescaped1); } static void check_mspel_pixels(void) diff --git a/tests/checkasm/vf_convolution.c b/tests/checkasm/vf_convolution.c index 007865863e5..3c3e9686727 100644 --- a/tests/checkasm/vf_convolution.c +++ b/tests/checkasm/vf_convolution.c @@ -20,7 +20,9 @@ #include "checkasm.h" #include "libavfilter/avfilter.h" #include "libavfilter/convolution.h" +#include "libavutil/avassert.h" #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "libavutil/mem_internal.h" #define WIDTH 512 @@ -38,9 +40,10 @@ static void check_sobel(const char * report_name) { - LOCAL_ALIGNED_32(uint8_t, src, [PIXELS]); - LOCAL_ALIGNED_32(uint8_t, dst_ref, [PIXELS]); - LOCAL_ALIGNED_32(uint8_t, dst_new, [PIXELS]); + uint8_t *src = av_malloc(PIXELS); + uint8_t *dst_ref_base = av_malloc(PIXELS); + uint8_t *dst_new = av_malloc(PIXELS); + uint8_t *dst_ref = dst_ref_base; const int height = WIDTH; const int width = HEIGHT; const int stride = SRC_STRIDE; @@ -62,6 +65,8 @@ static void check_sobel(const char * report_name) declare_func(void, uint8_t *dst, int width, float scale, float delta, const int *const matrix, const uint8_t *c[], int peak, int radius, int dstride, int stride, int size); + av_assert0(src && dst_ref && dst_new); + s.scale = scale; s.delta = delta; s.depth = 8; @@ -95,6 +100,9 @@ static void check_sobel(const char * report_name) } } + av_free(src); + av_free(dst_ref_base); + av_free(dst_new); } void checkasm_check_vf_sobel(void) diff --git a/tests/checkasm/vf_eq.c b/tests/checkasm/vf_eq.c index 1315b08f0ec..b98edde45fa 100644 --- a/tests/checkasm/vf_eq.c +++ b/tests/checkasm/vf_eq.c @@ -20,7 +20,9 @@ #include "checkasm.h" #include "libavfilter/avfilter.h" #include "libavfilter/vf_eq.h" +#include "libavutil/avassert.h" #include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" #include "libavutil/mem_internal.h" #define WIDTH 256 @@ -40,9 +42,9 @@ static void check_eq(void) { - LOCAL_ALIGNED_32(uint8_t, src, [PIXELS]); - LOCAL_ALIGNED_32(uint8_t, dst_ref, [PIXELS]); - LOCAL_ALIGNED_32(uint8_t, dst_new, [PIXELS]); + uint8_t *src = av_malloc(PIXELS); + uint8_t *dst_ref = av_malloc(PIXELS); + uint8_t *dst_new = av_malloc(PIXELS); int w = WIDTH; int h = HEIGHT; int src_stride = SRC_STRIDE; @@ -52,6 +54,8 @@ static void check_eq(void) declare_func(void, EQParameters *param, uint8_t *dst, int dst_stride, const uint8_t *src, int src_stride, int w, int h); + av_assert0(src && dst_ref && dst_new); + double rand_contrast = (int)(rnd() % (RANDOM_RANGE * 2) - RANDOM_RANGE) / (SCALE * 1.0); double rand_brightness = (int)(rnd() % (SCALE * 2) - SCALE) / @@ -71,6 +75,10 @@ static void check_eq(void) fail(); bench_new(&pa, dst_new, dst_stride, src, src_stride, w, h); } + + av_free(src); + av_free(dst_ref); + av_free(dst_new); } void checkasm_check_vf_eq(void) -- 2.54.0 _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]
