diff options
author | Niklas Haas <git@haasn.dev> | 2022-02-11 05:04:27 +0100 |
---|---|---|
committer | Niklas Haas <git@haasn.dev> | 2022-02-11 05:12:09 +0100 |
commit | ef83498aefb91168292439c88e01723880eb6707 (patch) | |
tree | 75b0ea1e192d4d5bfd0eee4984e162c5e8d18564 /video/out | |
parent | 4629fe577fa2adf2267bbf12bad29293d9ad61b3 (diff) | |
download | mpv-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.c | 39 |
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) |