summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2012-12-26 21:13:58 +0100
committerwm4 <wm4@nowhere>2013-01-13 20:04:13 +0100
commitc3788543f55199fc729a49f1402a9e13aaefbd85 (patch)
treebbb7d26875e9dcb03b096e048c18fb256abba00b
parente16fab8822b8c7fe6b8623d78da449cb2e93eeef (diff)
downloadmpv-c3788543f55199fc729a49f1402a9e13aaefbd85.tar.bz2
mpv-c3788543f55199fc729a49f1402a9e13aaefbd85.tar.xz
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)
-rw-r--r--video/filter/vf_expand.c101
-rw-r--r--video/memcpy_pic.h16
-rw-r--r--video/mp_image.c78
-rw-r--r--video/mp_image.h2
4 files changed, 88 insertions, 109 deletions
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 <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]);
+ }
}
}
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);