mirror of
https://github.com/mpv-player/mpv
synced 2025-02-16 12:17:12 +00:00
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:
parent
e16fab8822
commit
c3788543f5
@ -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){
|
||||
|
@ -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 */
|
||||
|
@ -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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user