summaryrefslogtreecommitdiffstats
path: root/video/out
diff options
context:
space:
mode:
authorNiklas Haas <git@haasn.dev>2022-02-11 05:04:27 +0100
committerNiklas Haas <git@haasn.dev>2022-02-11 05:12:09 +0100
commitef83498aefb91168292439c88e01723880eb6707 (patch)
tree75b0ea1e192d4d5bfd0eee4984e162c5e8d18564 /video/out
parent4629fe577fa2adf2267bbf12bad29293d9ad61b3 (diff)
downloadmpv-ef83498aefb91168292439c88e01723880eb6707.tar.bz2
mpv-ef83498aefb91168292439c88e01723880eb6707.tar.xz
vo_gpu_next: don't crash on negative plane strides
This is an annoying special case only really needed because of the `vflip` filter. mpv handles this by directly adjusting the plane transform. The libplacebo API, unfortunately, does not allow passing the required information for this to work smoothly. Long-term I plan on adding support for plane flipping in libplacebo directly, but for the meantime, we will have to work-around it by moving the flipping to the whole-image `crop` instead. Not an ideal solution but better than crashing. Fixes #9855
Diffstat (limited to 'video/out')
-rw-r--r--video/out/vo_gpu_next.c39
1 files changed, 34 insertions, 5 deletions
diff --git a/video/out/vo_gpu_next.c b/video/out/vo_gpu_next.c
index 599ea758d4..da613f498b 100644
--- a/video/out/vo_gpu_next.c
+++ b/video/out/vo_gpu_next.c
@@ -481,17 +481,36 @@ static bool map_frame(pl_gpu gpu, pl_tex *tex, const struct pl_source_frame *src
enum pl_chroma_location chroma = mp_chroma_to_pl(par->chroma_location);
int planes = plane_data_from_imgfmt(data, &frame->repr.bits, mpi->imgfmt);
+ bool img_vflipped = false;
for (int n = 0; n < planes; n++) {
data[n].width = mp_image_plane_w(mpi, n);
data[n].height = mp_image_plane_h(mpi, n);
- data[n].row_stride = mpi->stride[n];
- data[n].pixels = mpi->planes[n];
+ bool vflipped = mpi->stride[n] < 0;
+ if (vflipped) {
+ int h = mp_image_plane_h(mpi, n);
+ data[n].pixels = mpi->planes[n] + (h - 1) * mpi->stride[n];
+ data[n].row_stride = -mpi->stride[n];
+ } else {
+ data[n].pixels = mpi->planes[n];
+ data[n].row_stride = mpi->stride[n];
+ }
+
+ // libplacebo can't deal with images that have partially flipped
+ // textures. We could work around this by blitting them to fresh
+ // (unflipped) textures, but it's an unlikely enough case to warrant
+ // just erroring out instead. (Usually, all planes will be flipped or
+ // unflipped simultaneously, e.g. by the `vflip` filter)
+ if (n > 0 && img_vflipped != vflipped) {
+ MP_ERR(vo, "Inconsistently flipped planes!\n");
+ return false;
+ }
+ img_vflipped = vflipped;
pl_buf buf = get_dr_buf(mpi);
if (buf) {
- data[n].pixels = NULL;
data[n].buf = buf;
- data[n].buf_offset = mpi->planes[n] - buf->data;
+ data[n].buf_offset = (uint8_t *) data[n].pixels - buf->data;
+ data[n].pixels = NULL;
} else if (gpu->limits.callbacks) {
data[n].callback = talloc_free;
data[n].priv = mp_image_new_ref(mpi);
@@ -504,8 +523,11 @@ static bool map_frame(pl_gpu gpu, pl_tex *tex, const struct pl_source_frame *src
return false;
}
- if (mpi->fmt.xs[n] || mpi->fmt.ys[n])
+ if (mpi->fmt.xs[n] || mpi->fmt.ys[n]) {
pl_chroma_location_offset(chroma, &plane->shift_x, &plane->shift_y);
+ if (vflipped)
+ plane->shift_y = -plane->shift_y;
+ }
}
#ifdef PL_HAVE_LAV_DOLBY_VISION
@@ -668,6 +690,13 @@ static void apply_crop(struct pl_frame *frame, struct mp_rect crop,
frame->crop.y0 = height - frame->crop.y0;
frame->crop.y1 = height - frame->crop.y1;
}
+
+ struct mp_image *mpi = frame->user_data;
+ if (mpi && mpi->stride[0] < 0) {
+ // Adjust for vertically flipped planes
+ frame->crop.y0 = height - frame->crop.y0;
+ frame->crop.y1 = height - frame->crop.y1;
+ }
}
static void draw_frame(struct vo *vo, struct vo_frame *frame)