gl_video: handle non-mod-2 4:2:0 YUV video correctly

Allocate textures big enough to include the bottom/right borders (so the
chroma texture sizes are rounded up instead of down). Make the texture
large enough to include the additional luma border. Conceptually, we
pretend that the video frame is fully aligned, and then crop away the
unwanted borders. Filtering (even just bilinear) will access the
borders anyway, so it's possible that we might need to switch to
"harder" cropping instead, but at least pixels not close to the
border should be displayed correctly now.

Add a comment to mp_image.c about this luma border. These semantics are
kind of subtle, and the image allocation code handle this in a subtle
way too, so it's better to document this explicitly. The libavutil
image allocation code does similar things.
This commit is contained in:
wm4 2013-08-06 20:09:31 +02:00
parent 57ec67a6cc
commit d40a91e804
2 changed files with 14 additions and 2 deletions

View File

@ -125,6 +125,10 @@ static void mp_image_alloc_planes(struct mp_image *mpi)
{ {
assert(!mpi->planes[0]); assert(!mpi->planes[0]);
// Note: for non-mod-2 4:2:0 YUV frames, we have to allocate an additional
// top/right border. This is needed for correct handling of such
// images in filter and VO code (e.g. vo_vdpau or vo_opengl).
size_t plane_size[MP_MAX_PLANES]; size_t plane_size[MP_MAX_PLANES];
for (int n = 0; n < MP_MAX_PLANES; n++) { for (int n = 0; n < MP_MAX_PLANES; n++) {
int alloc_h = MP_ALIGN_UP(mpi->h, 32) >> mpi->fmt.ys[n]; int alloc_h = MP_ALIGN_UP(mpi->h, 32) >> mpi->fmt.ys[n];

View File

@ -1207,13 +1207,21 @@ static void init_video(struct gl_video *p)
debug_check_gl(p, "before video texture creation"); debug_check_gl(p, "before video texture creation");
// For video with odd sizes: enlarge the luma texture so that it covers all
// chroma pixels - then we can render these correctly by cropping the final
// image (conceptually).
// Image allocations are always such that the "additional" luma border
// exists and can be accessed.
int full_w = MP_ALIGN_UP(p->image_w, 1 << p->image_desc.chroma_xs);
int full_h = MP_ALIGN_UP(p->image_h, 1 << p->image_desc.chroma_ys);
struct video_image *vimg = &p->image; struct video_image *vimg = &p->image;
for (int n = 0; n < p->plane_count; n++) { for (int n = 0; n < p->plane_count; n++) {
struct texplane *plane = &vimg->planes[n]; struct texplane *plane = &vimg->planes[n];
plane->w = p->image_w >> p->image_desc.xs[n]; plane->w = full_w >> p->image_desc.xs[n];
plane->h = p->image_h >> p->image_desc.ys[n]; plane->h = full_h >> p->image_desc.ys[n];
tex_size(p, plane->w, plane->h, tex_size(p, plane->w, plane->h,
&plane->tex_w, &plane->tex_h); &plane->tex_w, &plane->tex_h);