From b4f400b018552a62bc479c77fd9b91f22838f070 Mon Sep 17 00:00:00 2001 From: Sebastian Reimers Date: Tue, 10 Dec 2024 08:05:30 +0100 Subject: [PATCH 1/2] rem/vidconv: add vidconv_center and x and y source offsets --- include/rem_vid.h | 2 + include/rem_vidconv.h | 2 + rem/vidconv/vconv.c | 311 ++++++++++++++++++++++-------------------- test/vidconv.c | 64 ++++++++- 4 files changed, 229 insertions(+), 150 deletions(-) diff --git a/include/rem_vid.h b/include/rem_vid.h index 4103477c0..3071d345c 100644 --- a/include/rem_vid.h +++ b/include/rem_vid.h @@ -55,6 +55,8 @@ struct vidframe { uint16_t linesize[4]; /**< Array of line-sizes */ struct vidsz size; /**< Frame resolution */ enum vidfmt fmt; /**< Video pixel format */ + unsigned xoffs; /**< x offset */ + unsigned yoffs; /**< y offset */ }; /** Video point */ diff --git a/include/rem_vidconv.h b/include/rem_vidconv.h index 94fee1d65..44120f4d9 100644 --- a/include/rem_vidconv.h +++ b/include/rem_vidconv.h @@ -9,3 +9,5 @@ void vidconv(struct vidframe *dst, const struct vidframe *src, struct vidrect *r); void vidconv_aspect(struct vidframe *dst, const struct vidframe *src, struct vidrect *r); +void vidconv_center(struct vidframe *dst, const struct vidframe *src, + struct vidrect *r); diff --git a/rem/vidconv/vconv.c b/rem/vidconv/vconv.c index b0a320786..97840d113 100644 --- a/rem/vidconv/vconv.c +++ b/rem/vidconv/vconv.c @@ -180,31 +180,29 @@ static inline void _yuv2rgb(uint8_t *rgb, uint8_t y, uint8_t u, uint8_t v) } -typedef void (line_h)(unsigned xoffs, unsigned width, double rw, - unsigned yd, unsigned ys, unsigned ys2, - uint8_t *dd0, uint8_t *dd1, uint8_t *dd2, - unsigned lsd, - const uint8_t *sd0, const uint8_t *sd1, - const uint8_t *sd2, unsigned lss); - - -static void yuv420p_to_yuv420p(unsigned xoffs, unsigned width, double rw, - unsigned yd, unsigned ys, unsigned ys2, - uint8_t *dd0, uint8_t *dd1, uint8_t *dd2, - unsigned lsd, +typedef void(line_h)(unsigned xsoffs, unsigned xdoffs, unsigned width, + double rw, unsigned yd, unsigned ys, unsigned ys2, + uint8_t *dd0, uint8_t *dd1, uint8_t *dd2, unsigned lsd, + const uint8_t *sd0, const uint8_t *sd1, + const uint8_t *sd2, unsigned lss); + + +static void yuv420p_to_yuv420p(unsigned xsoffs, unsigned xdoffs, + unsigned width, double rw, unsigned yd, + unsigned ys, unsigned ys2, uint8_t *dd0, + uint8_t *dd1, uint8_t *dd2, unsigned lsd, const uint8_t *ds0, const uint8_t *ds1, - const uint8_t *ds2, unsigned lss - ) + const uint8_t *ds2, unsigned lss) { unsigned x, xd, xs, xs2; unsigned id, is; for (x=0; x>1) + (ys>>1)*lss/2; @@ -423,12 +417,12 @@ static void yuv420p_to_rgb32(unsigned xoffs, unsigned width, double rw, } -static void yuv420p_to_rgb565(unsigned xoffs, unsigned width, double rw, - unsigned yd, unsigned ys, unsigned ys2, - uint8_t *dd0, uint8_t *dd1, uint8_t *dd2, - unsigned lsd, - const uint8_t *ds0, const uint8_t *ds1, - const uint8_t *ds2, unsigned lss) +static void yuv420p_to_rgb565(unsigned xsoffs, unsigned xdoffs, unsigned width, + double rw, unsigned yd, unsigned ys, + unsigned ys2, uint8_t *dd0, uint8_t *dd1, + uint8_t *dd2, unsigned lsd, const uint8_t *ds0, + const uint8_t *ds1, const uint8_t *ds2, + unsigned lss) { unsigned x, xd, xs, xs2; unsigned id, is; @@ -441,10 +435,10 @@ static void yuv420p_to_rgb565(unsigned xoffs, unsigned width, double rw, int ruv, guv, buv; uint8_t u, v; - xd = (x + xoffs) * 2; + xd = (x + xdoffs) * 2; - xs = (unsigned)(x * rw); - xs2 = (unsigned)((x+1) * rw); + xs = (unsigned)((x + xsoffs) * rw); + xs2 = (unsigned)((x + xsoffs + 1) * rw); id = (xd + yd*lsd); is = (xs>>1) + (ys>>1)*lss/2; @@ -464,13 +458,12 @@ static void yuv420p_to_rgb565(unsigned xoffs, unsigned width, double rw, } -static void nv12_to_yuv420p(unsigned xoffs, unsigned width, double rw, - unsigned yd, unsigned ys, unsigned ys2, +static void nv12_to_yuv420p(unsigned xsoffs, unsigned xdoffs, unsigned width, + double rw, unsigned yd, unsigned ys, unsigned ys2, uint8_t *dd0, uint8_t *dd1, uint8_t *dd2, - unsigned lsd, - const uint8_t *ds0, const uint8_t *ds1, - const uint8_t *ds2, unsigned lss - ) + unsigned lsd, const uint8_t *ds0, + const uint8_t *ds1, const uint8_t *ds2, + unsigned lss) { unsigned x, xd, xs, xs2; unsigned id, is; @@ -479,10 +472,10 @@ static void nv12_to_yuv420p(unsigned xoffs, unsigned width, double rw, for (x=0; xy; - ys = (unsigned)(y * rh); - ys2 = (unsigned)((y+1) * rh); + ys = (unsigned)((y + src->yoffs) * rh); + ys2 = (unsigned)((y + src->yoffs + 1) * rh); - lineh(r->x, r->w, rw, yd, ys, ys2, + lineh(src->xoffs, r->x, r->w, rw, yd, ys, ys2, dd0, dd1, dd2, lsd, ds0, ds1, ds2, lss); } @@ -824,3 +812,32 @@ void vidconv_aspect(struct vidframe *dst, const struct vidframe *src, vidconv(dst, src, r); } + + +/** + * Same as vidconv(), but maintain source min. center within bounds of r + * + * @param dst Destination video frame + * @param src Source video frame + * @param r Drawing area in destination frame + */ +void vidconv_center(struct vidframe *dst, const struct vidframe *src, + struct vidrect *r) +{ + struct vidframe sc = *src; + + if (src->size.w >= src->size.h) { + double rh = (double)src->size.h / (double)r->h; + sc.size.w = + (unsigned)min((double)src->size.w, (double)r->w * rh); + sc.xoffs = ((unsigned)(src->size.w / rh) - r->w) / 2; + } + else { + double rw = (double)src->size.w / (double)r->w; + sc.size.h = + (unsigned)min((double)src->size.h, (double)r->h * rw); + sc.yoffs = ((unsigned)(src->size.h / rw) - r->h) / 2; + } + + vidconv(dst, &sc, r); +} diff --git a/test/vidconv.c b/test/vidconv.c index d4bf8bf01..c9bd5c0c7 100644 --- a/test/vidconv.c +++ b/test/vidconv.c @@ -157,9 +157,7 @@ static void write_pattern(uint8_t *buf, size_t len) */ static int test_vidconv_scaling_base(enum vidfmt via_fmt) { -#define WIDTH 40 -#define HEIGHT 30 -#define SCALE 2 + enum { WIDTH = 40, HEIGHT = 30, SCALE = 2 }; struct vidframe *f0 = NULL, *f1 = NULL, *f2 = NULL; const struct vidsz size0 = {WIDTH, HEIGHT}; const struct vidsz size1 = {WIDTH*SCALE, HEIGHT*SCALE}; @@ -369,12 +367,72 @@ int test_vidconv_pixel_formats(void) } +static int test_vidconv_center(void) +{ + int err; + struct vidframe *dst = NULL; + struct vidframe *src = NULL; + + static struct test { + struct vidrect r; + struct vidsz src_sz; + struct vidsz dst_sz; + } testv[] = { + {.r = {.x = 0, .y = 0, .w = 960, .h = 1080}, + .src_sz = {.w = 320, .h = 180}, + .dst_sz = {.w = 1920, .h = 1080}}, + {.r = {.x = 0, .y = 0, .w = 960, .h = 1080}, + .src_sz = {.w = 180, .h = 320}, + .dst_sz = {.w = 1920, .h = 1080}}, + {.r = {.x = 0, .y = 0, .w = 960, .h = 1080}, + .src_sz = {.w = 1920, .h = 1080}, + .dst_sz = {.w = 1920, .h = 1080}}, + {.r = {.x = 0, .y = 0, .w = 960, .h = 1080}, + .src_sz = {.w = 1080, .h = 1920}, + .dst_sz = {.w = 1920, .h = 1080}}, + {.r = {.x = 0, .y = 0, .w = 640, .h = 720}, + .src_sz = {.w = 1920, .h = 1080}, + .dst_sz = {.w = 1280, .h = 720}}, + {.r = {.x = 960, .y = 0, .w = 960, .h = 1080}, + .src_sz = {.w = 1024, .h = 768}, /* 4:3 */ + .dst_sz = {.w = 1920, .h = 1080}}, + {.r = {.x = 0, .y = 0, .w = 960, .h = 1080}, + .src_sz = {.w = 320, .h = 320}, /* square */ + .dst_sz = {.w = 1920, .h = 1080}}, + }; + + for (size_t i = 0; i < RE_ARRAY_SIZE(testv); i++) { + struct test *test = &testv[i]; + + err = vidframe_alloc(&src, VID_FMT_YUV420P, &test->src_sz); + err |= vidframe_alloc(&dst, VID_FMT_YUV420P, &test->dst_sz); + TEST_ERR(err); + + vidconv_center(dst, src, &test->r); + + src = mem_deref(src); + dst = mem_deref(dst); + } + +out: + src = mem_deref(src); + dst = mem_deref(dst); + + return err; +} + + int test_vidconv(void) { int err; err = test_vid_rgb2yuv(); + TEST_ERR(err); + + err = test_vidconv_center(); + TEST_ERR(err); +out: return err; } From caf530d2374a8b0378df0501ab6a407c18cab702 Mon Sep 17 00:00:00 2001 From: Sebastian Reimers Date: Tue, 10 Dec 2024 08:08:18 +0100 Subject: [PATCH 2/2] vidmix/source_mix: use vidconv_center (full height center) --- rem/vidmix/vidmix.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/rem/vidmix/vidmix.c b/rem/vidmix/vidmix.c index 4eeb4e5d0..f4a3b5e73 100644 --- a/rem/vidmix/vidmix.c +++ b/rem/vidmix/vidmix.c @@ -132,6 +132,14 @@ static inline void source_mix(struct vidframe *mframe, source_mix_full(mframe, frame_src); return; } + else if (n <= 3) { + rect.w = mframe->size.w / n; + rect.h = mframe->size.h; + rect.x = (rect.w) * (idx % n); + rect.y = 0; + vidconv_center(mframe, frame_src, &rect); + return; + } else { rect.w = mframe->size.w / rows; rect.h = mframe->size.h / rows;