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)
This commit is contained in:
wm4 2012-12-26 21:13:58 +01:00
parent e16fab8822
commit c3788543f5
4 changed files with 88 additions and 109 deletions

View File

@ -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;
}
struct mp_imgfmt_desc fmt = mp_imgfmt_get_desc(outfmt);
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);
}
// 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);
}
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){

View File

@ -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 */

View File

@ -25,6 +25,7 @@
#include <libavutil/mem.h>
#include <libavutil/common.h>
#include <libavutil/bswap.h>
#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]);
}
}
}

View File

@ -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);