From 82231fd74d173fb47845dd086d360bceb3e5fc17 Mon Sep 17 00:00:00 2001 From: wm4 Date: Sat, 1 Oct 2016 16:07:51 +0200 Subject: vo_opengl: attempt to fix chroma offset under rotation and flipping Other than being overly convoluted, this seems to make sense to me. Except that to get the "rot" transform I have to set flip=true, which makes no sense at all to me. --- video/out/opengl/video.c | 63 ++++++++++++++++++++++++++++++++++++------------ 1 file changed, 48 insertions(+), 15 deletions(-) (limited to 'video/out/opengl/video.c') diff --git a/video/out/opengl/video.c b/video/out/opengl/video.c index 7d7641a1ea..c3b3660c78 100644 --- a/video/out/opengl/video.c +++ b/video/out/opengl/video.c @@ -728,11 +728,12 @@ static int pass_bind(struct gl_video *p, struct img_tex tex) } // Rotation by 90° and flipping. -static void get_plane_source_transform(struct gl_video *p, struct texplane *t, - struct gl_transform *out_tr) +// w/h is used for recentering. +static void get_transform(float w, float h, int rotate, bool flip, + struct gl_transform *out_tr) { struct gl_transform tr = identity_trans; - int a = p->image_params.rotate % 90 ? 0 : p->image_params.rotate / 90; + int a = rotate % 90 ? 0 : rotate / 90; int sin90[4] = {0, 1, 0, -1}; // just to avoid rounding issues etc. int cos90[4] = {1, 0, -1, 0}; struct gl_transform rot = {{{cos90[a], sin90[a]}, {-sin90[a], cos90[a]}}}; @@ -741,17 +742,24 @@ static void get_plane_source_transform(struct gl_video *p, struct texplane *t, // basically, recenter to keep the whole image in view float b[2] = {1, 1}; gl_transform_vec(rot, &b[0], &b[1]); - tr.t[0] += b[0] < 0 ? t->w : 0; - tr.t[1] += b[1] < 0 ? t->h : 0; + tr.t[0] += b[0] < 0 ? w : 0; + tr.t[1] += b[1] < 0 ? h : 0; - if (t->flipped) { - struct gl_transform flip = {{{1, 0}, {0, -1}}, {0, t->h}}; - gl_transform_trans(flip, &tr); + if (flip) { + struct gl_transform fliptr = {{{1, 0}, {0, -1}}, {0, h}}; + gl_transform_trans(fliptr, &tr); } *out_tr = tr; } +// Return the chroma plane upscaled to luma size, but with additional padding +// for image sizes not aligned to subsampling. +static int chroma_upsize(int size, int shift) +{ + return mp_chroma_div_up(size, shift) << shift; +} + // Places a video_image's image textures + associated metadata into tex[]. The // number of textures is equal to p->plane_count. Any necessary plane offsets // are stored in off. (e.g. chroma position) @@ -760,13 +768,13 @@ static void pass_get_img_tex(struct gl_video *p, struct video_image *vimg, { assert(vimg->mpi); + int w = p->image_params.w; + int h = p->image_params.h; + // Determine the chroma offset float ls_w = 1.0 / (1 << p->image_desc.chroma_xs); float ls_h = 1.0 / (1 << p->image_desc.chroma_ys); - if (p->image_params.rotate % 180 == 90) - MPSWAP(float, ls_w, ls_h); - struct gl_transform chroma = {{{ls_w, 0.0}, {0.0, ls_h}}}; if (p->image_params.chroma_location != MP_CHROMA_CENTER) { @@ -781,8 +789,6 @@ static void pass_get_img_tex(struct gl_video *p, struct video_image *vimg, chroma.t[1] = ls_h < 1 ? ls_h * -cy / 2 : 0; } - // FIXME: account for rotation in the chroma offset - // The existing code assumes we just have a single tex multiplier for // all of the planes. This may change in the future float tex_mul = 1.0 / mp_get_csp_mul(p->image_params.color.space, @@ -819,11 +825,38 @@ static void pass_get_img_tex(struct gl_video *p, struct video_image *vimg, .components = p->image_desc.components[n], }; snprintf(tex[n].swizzle, sizeof(tex[n].swizzle), "%s", t->swizzle); - get_plane_source_transform(p, t, &tex[n].transform); + get_transform(t->w, t->h, p->image_params.rotate, t->flipped, + &tex[n].transform); if (p->image_params.rotate % 180 == 90) MPSWAP(int, tex[n].w, tex[n].h); - off[n] = type == PLANE_CHROMA ? chroma : identity_trans; + off[n] = identity_trans; + + if (type == PLANE_CHROMA) { + struct gl_transform rot; + get_transform(0, 0, p->image_params.rotate, true, &rot); + + struct gl_transform tr = chroma; + gl_transform_vec(rot, &tr.t[0], &tr.t[1]); + + float dx = (chroma_upsize(w, p->image_desc.xs[n]) - w) * ls_w; + float dy = (chroma_upsize(h, p->image_desc.ys[n]) - h) * ls_h; + + // Adjust the chroma offset if the real chroma size is fractional + // due image sizes not aligned to chroma subsampling. + struct gl_transform rot2; + get_transform(0, 0, p->image_params.rotate, t->flipped, &rot2); + if (rot2.m[0][0] < 0) + tr.t[0] += dx; + if (rot2.m[1][0] < 0) + tr.t[0] += dy; + if (rot2.m[0][1] < 0) + tr.t[1] += dx; + if (rot2.m[1][1] < 0) + tr.t[1] += dy; + + off[n] = tr; + } } } -- cgit v1.2.3