From c3788543f55199fc729a49f1402a9e13aaefbd85 Mon Sep 17 00:00:00 2001 From: wm4 Date: Wed, 26 Dec 2012 21:13:58 +0100 Subject: vf_expand: support more image formats This did random things with some image formats, including 10 bit formats. Fixes the mp_image_clear() function too. This still has some caveats: - doesn't clear alpha to opaque (too hard with packed RGB, and is rarely needed) - sets luma to 0 for mpeg-range YUV, instead of the lowest possible value (e.g. 16 for 8 bit) --- video/filter/vf_expand.c | 101 ++++++++++++++++------------------------------- video/memcpy_pic.h | 16 ++++++++ video/mp_image.c | 78 ++++++++++++++++++------------------ video/mp_image.h | 2 +- 4 files changed, 88 insertions(+), 109 deletions(-) (limited to 'video') diff --git a/video/filter/vf_expand.c b/video/filter/vf_expand.c index f8ebbd0b18..ff84d7670c 100644 --- a/video/filter/vf_expand.c +++ b/video/filter/vf_expand.c @@ -63,10 +63,6 @@ static int config(struct vf_instance *vf, int width, int height, int d_width, int d_height, unsigned int flags, unsigned int outfmt) { - struct MPOpts *opts = vf->opts; - mp_image_t test_mpi; - mp_image_setfmt(&test_mpi, outfmt); - if (test_mpi.num_planes > 3 || !test_mpi.bpp) return 0; vf->priv->exp_x = vf->priv->cfg_exp_x; vf->priv->exp_y = vf->priv->cfg_exp_y; vf->priv->exp_w = vf->priv->cfg_exp_w; @@ -99,89 +95,58 @@ static int config(struct vf_instance *vf, if(vf->priv->exp_x<0 || vf->priv->exp_x+width>vf->priv->exp_w) vf->priv->exp_x=(vf->priv->exp_w-width)/2; if(vf->priv->exp_y<0 || vf->priv->exp_y+height>vf->priv->exp_h) vf->priv->exp_y=(vf->priv->exp_h-height)/2; - if(test_mpi.flags & MP_IMGFLAG_YUV) { - int x_align_mask = (1 << test_mpi.chroma_x_shift) - 1; - int y_align_mask = (1 << test_mpi.chroma_y_shift) - 1; - // For 1-plane format non-aligned offsets will completely - // destroy the colours, for planar it will break the chroma - // sampling position. - if (vf->priv->exp_x & x_align_mask) { - vf->priv->exp_x &= ~x_align_mask; - mp_msg(MSGT_VFILTER, MSGL_ERR, "Specified x offset not supported " - "for YUV, reduced to %i.\n", vf->priv->exp_x); - } - if (vf->priv->exp_y & y_align_mask) { - vf->priv->exp_y &= ~y_align_mask; - mp_msg(MSGT_VFILTER, MSGL_ERR, "Specified y offset not supported " - "for YUV, reduced to %i.\n", vf->priv->exp_y); - } - } - if(!opts->screen_size_x && !opts->screen_size_y){ - d_width=d_width*vf->priv->exp_w/width; - d_height=d_height*vf->priv->exp_h/height; - } - return vf_next_config(vf,vf->priv->exp_w,vf->priv->exp_h,d_width,d_height,flags,outfmt); -} + struct mp_imgfmt_desc fmt = mp_imgfmt_get_desc(outfmt); -// w, h = width and height of the source frame (located at exp_x/exp_y) -static void clear_borders(struct vf_instance *vf, struct mp_image *dmpi, - int w, int h) -{ - // upper border (over the full width) - mp_image_clear(dmpi, 0, 0, vf->priv->exp_w, vf->priv->exp_y); - // lower border - mp_image_clear(dmpi, 0, vf->priv->exp_y + h, vf->priv->exp_w, - vf->priv->exp_h - (vf->priv->exp_y + h)); - // left - mp_image_clear(dmpi, 0, vf->priv->exp_y, vf->priv->exp_x, h); - // right - mp_image_clear(dmpi, vf->priv->exp_x + w, vf->priv->exp_y, - vf->priv->exp_w - (vf->priv->exp_x + w), h); + vf->priv->exp_x = MP_ALIGN_DOWN(vf->priv->exp_x, fmt.align_x); + vf->priv->exp_y = MP_ALIGN_DOWN(vf->priv->exp_y, fmt.align_y); + + vf_rescale_dsize(vf, &d_width, &d_height, width, height, + vf->priv->exp_w, vf->priv->exp_h); + + return vf_next_config(vf,vf->priv->exp_w,vf->priv->exp_h,d_width,d_height,flags,outfmt); } static struct mp_image *filter(struct vf_instance *vf, struct mp_image *mpi) { - if (vf->priv->exp_x == 0 && vf->priv->exp_y == 0 && - vf->priv->exp_w == mpi->w && vf->priv->exp_h == mpi->h) + int e_x = vf->priv->exp_x, e_y = vf->priv->exp_y; + int e_w = vf->priv->exp_w, e_h = vf->priv->exp_h; + + if (e_x == 0 && e_y == 0 && e_w == mpi->w && e_h == mpi->h) return mpi; struct mp_image *dmpi = vf_alloc_out_image(vf); mp_image_copy_attributes(dmpi, mpi); - // copy mpi->dmpi... - if(mpi->flags&MP_IMGFLAG_PLANAR){ - memcpy_pic(dmpi->planes[0]+ - vf->priv->exp_y*dmpi->stride[0]+vf->priv->exp_x, - mpi->planes[0], mpi->w, mpi->h, - dmpi->stride[0],mpi->stride[0]); - memcpy_pic(dmpi->planes[1]+ - (vf->priv->exp_y>>mpi->chroma_y_shift)*dmpi->stride[1]+(vf->priv->exp_x>>mpi->chroma_x_shift), - mpi->planes[1], (mpi->w>>mpi->chroma_x_shift), (mpi->h>>mpi->chroma_y_shift), - dmpi->stride[1],mpi->stride[1]); - memcpy_pic(dmpi->planes[2]+ - (vf->priv->exp_y>>mpi->chroma_y_shift)*dmpi->stride[2]+(vf->priv->exp_x>>mpi->chroma_x_shift), - mpi->planes[2], (mpi->w>>mpi->chroma_x_shift), (mpi->h>>mpi->chroma_y_shift), - dmpi->stride[2],mpi->stride[2]); - } else { - memcpy_pic(dmpi->planes[0]+ - vf->priv->exp_y*dmpi->stride[0]+vf->priv->exp_x*(dmpi->bpp/8), - mpi->planes[0], mpi->w*(dmpi->bpp/8), mpi->h, - dmpi->stride[0],mpi->stride[0]); - } - clear_borders(vf, dmpi, mpi->w, mpi->h); + struct mp_image cropped = *dmpi; + mp_image_crop(&cropped, e_x, e_y, e_x + mpi->w, e_y + mpi->h); + mp_image_copy(&cropped, mpi); + + int e_x2 = e_x + MP_ALIGN_DOWN(mpi->w, mpi->fmt.align_x); + int e_y2 = e_y + MP_ALIGN_DOWN(mpi->h, mpi->fmt.align_y); + + // top border (over the full width) + mp_image_clear(dmpi, 0, 0, e_w, e_y); + // bottom border (over the full width) + mp_image_clear(dmpi, 0, e_y2, e_w, e_h); + // left + mp_image_clear(dmpi, 0, e_y, e_x, e_y2); + // right + mp_image_clear(dmpi, e_x2, e_y, e_w, e_y2); + talloc_free(mpi); return dmpi; } -//===========================================================================// - static int control(struct vf_instance *vf, int request, void* data){ return vf_next_control(vf,request,data); } -static int query_format(struct vf_instance *vf, unsigned int fmt){ - return vf_next_query_format(vf,fmt); +static int query_format(struct vf_instance *vf, unsigned int fmt) +{ + if (!IMGFMT_IS_HWACCEL(fmt)) + return vf_next_query_format(vf, fmt); + return 0; } static int vf_open(vf_instance_t *vf, char *args){ diff --git a/video/memcpy_pic.h b/video/memcpy_pic.h index 2def66f3a4..5343739e82 100644 --- a/video/memcpy_pic.h +++ b/video/memcpy_pic.h @@ -70,4 +70,20 @@ static inline void memset_pic(void *dst, int fill, int bytesPerLine, int height, } } +static inline void memset16_pic(void *dst, int fill, int unitsPerLine, + int height, int stride) +{ + if (fill == 0) { + memset_pic(dst, 0, unitsPerLine * 2, height, stride); + } else { + for (int i = 0; i < height; i++) { + uint16_t *line = dst; + uint16_t *end = line + unitsPerLine; + while (line < end) + *line++ = fill; + dst = (uint8_t *)dst + stride; + } + } +} + #endif /* MPLAYER_FASTMEMCPY_H */ diff --git a/video/mp_image.c b/video/mp_image.c index 256e908198..832dec98fd 100644 --- a/video/mp_image.c +++ b/video/mp_image.c @@ -25,6 +25,7 @@ #include #include +#include #include "talloc.h" @@ -357,48 +358,45 @@ void mp_image_crop_rc(struct mp_image *img, struct mp_rect rc) mp_image_crop(img, rc.x0, rc.y0, rc.x1, rc.y1); } -void mp_image_clear(struct mp_image *mpi, int x0, int y0, int w, int h) +// Bottom/right border is allowed not to be aligned, but it might implicitly +// overwrite pixel data until the alignment (align_x/align_y) is reached. +void mp_image_clear(struct mp_image *img, int x0, int y0, int x1, int y1) { - int y; - if (mpi->flags & MP_IMGFLAG_PLANAR) { - y0 &= ~1; - h += h & 1; - for (y = y0; y < y0 + h; y += 2) { - memset(mpi->planes[0] + x0 + mpi->stride[0] * y, 0, w); - memset(mpi->planes[0] + x0 + mpi->stride[0] * (y + 1), 0, w); - memset(mpi->planes[1] + (x0 >> mpi->chroma_x_shift) + - mpi->stride[1] * (y >> mpi->chroma_y_shift), - 128, (w >> mpi->chroma_x_shift)); - memset(mpi->planes[2] + (x0 >> mpi->chroma_x_shift) + - mpi->stride[2] * (y >> mpi->chroma_y_shift), - 128, (w >> mpi->chroma_x_shift)); - } - return; + assert(x0 >= 0 && y0 >= 0); + assert(x0 <= x1 && y0 <= y1); + assert(x1 <= img->w && y1 <= img->h); + assert(!(x0 & (img->fmt.align_x - 1))); + assert(!(y0 & (img->fmt.align_y - 1))); + + struct mp_image area = *img; + mp_image_crop(&area, x0, y0, x1, y1); + + uint32_t plane_clear[MP_MAX_PLANES] = {0}; + + if (area.imgfmt == IMGFMT_YUYV) { + plane_clear[0] = av_le2ne16(0x8000); + } else if (area.imgfmt == IMGFMT_UYVY) { + plane_clear[0] = av_le2ne16(0x0080); + } else if (area.imgfmt == IMGFMT_NV12 || area.imgfmt == IMGFMT_NV21) { + plane_clear[1] = 0x8080; + } else if (area.flags & MP_IMGFLAG_YUV_P) { + uint16_t chroma_clear = (1 << area.fmt.plane_bits) / 2; + if (!(area.flags & MP_IMGFLAG_NE)) + chroma_clear = av_bswap16(chroma_clear); + if (area.num_planes > 2) + plane_clear[1] = plane_clear[2] = chroma_clear; } - // packed: - for (y = y0; y < y0 + h; y++) { - unsigned char *dst = mpi->planes[0] + mpi->stride[0] * y + - (mpi->bpp >> 3) * x0; - if (mpi->flags & MP_IMGFLAG_YUV) { - unsigned int *p = (unsigned int *) dst; - int size = (mpi->bpp >> 3) * w / 4; - int i; -#if BYTE_ORDER == BIG_ENDIAN -#define CLEAR_PACKEDYUV_PATTERN 0x00800080 -#define CLEAR_PACKEDYUV_PATTERN_SWAPPED 0x80008000 -#else -#define CLEAR_PACKEDYUV_PATTERN 0x80008000 -#define CLEAR_PACKEDYUV_PATTERN_SWAPPED 0x00800080 -#endif - int clear = CLEAR_PACKEDYUV_PATTERN; - if (mpi->imgfmt == IMGFMT_UYVY) - clear = CLEAR_PACKEDYUV_PATTERN_SWAPPED; - for (i = 0; i < size - 3; i += 4) - p[i] = p[i + 1] = p[i + 2] = p[i + 3] = clear; - for (; i < size; i++) - p[i] = clear; - } else - memset(dst, 0, (mpi->bpp >> 3) * w); + + for (int p = 0; p < area.num_planes; p++) { + int bpp = area.fmt.bpp[p]; + int bytes = (area.plane_w[p] * bpp + 7) / 8; + if (bpp <= 8) { + memset_pic(area.planes[p], plane_clear[p], bytes, + area.plane_h[p], area.stride[p]); + } else { + memset16_pic(area.planes[p], plane_clear[p], (bytes + 1) / 2, + area.plane_h[p], area.stride[p]); + } } } diff --git a/video/mp_image.h b/video/mp_image.h index f5f246021a..dd2c451a0b 100644 --- a/video/mp_image.h +++ b/video/mp_image.h @@ -92,7 +92,6 @@ typedef struct mp_image { } mp_image_t; struct mp_image *mp_image_alloc(unsigned int fmt, int w, int h); -void mp_image_clear(struct mp_image *mpi, int x0, int y0, int w, int h); void mp_image_copy(struct mp_image *dmpi, struct mp_image *mpi); void mp_image_copy_attributes(struct mp_image *dmpi, struct mp_image *mpi); struct mp_image *mp_image_new_copy(struct mp_image *img); @@ -102,6 +101,7 @@ void mp_image_make_writeable(struct mp_image *img); void mp_image_setrefp(struct mp_image **p_img, struct mp_image *new_value); void mp_image_unrefp(struct mp_image **p_img); +void mp_image_clear(struct mp_image *mpi, int x0, int y0, int x1, int y1); void mp_image_crop(struct mp_image *img, int x0, int y0, int x1, int y1); void mp_image_crop_rc(struct mp_image *img, struct mp_rect rc); -- cgit v1.2.3