summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--DOCS/man/en/vo.rst4
-rw-r--r--video/csputils.c19
-rw-r--r--video/csputils.h10
-rw-r--r--video/decode/vd_lavc.c3
-rw-r--r--video/filter/vf.c1
-rw-r--r--video/mp_image.c1
-rw-r--r--video/mp_image.h3
-rw-r--r--video/out/gl_video.c27
-rw-r--r--video/out/gl_video.h1
-rw-r--r--video/out/gl_video_shaders.glsl8
10 files changed, 74 insertions, 3 deletions
diff --git a/DOCS/man/en/vo.rst b/DOCS/man/en/vo.rst
index 079e146f8a..3b2c280724 100644
--- a/DOCS/man/en/vo.rst
+++ b/DOCS/man/en/vo.rst
@@ -465,6 +465,10 @@ opengl
that when using FBO indirections (such as with ``opengl-hq``), a FBO
format with alpha must be specified with the ``fbo-format`` option.
+ chroma-location=<auto|center|left>
+ Set the YUV chroma sample location. auto means use the bitstream
+ flags (default: auto).
+
opengl-hq
Same as ``opengl``, but with default settings for high quality rendering.
diff --git a/video/csputils.c b/video/csputils.c
index 240c7a3259..91b7d88ec6 100644
--- a/video/csputils.c
+++ b/video/csputils.c
@@ -100,6 +100,25 @@ enum mp_csp mp_csp_guess_colorspace(int width, int height)
return width >= 1280 || height > 576 ? MP_CSP_BT_709 : MP_CSP_BT_601;
}
+enum mp_chroma_location avchroma_location_to_mp(enum AVChromaLocation loc)
+{
+ switch (loc) {
+ case AVCHROMA_LOC_LEFT: return MP_CHROMA_LEFT;
+ case AVCHROMA_LOC_CENTER: return MP_CHROMA_CENTER;
+ default: return MP_CHROMA_AUTO;
+ }
+}
+
+// Return location of chroma samples relative to luma samples. 0/0 means
+// centered. Other possible values are -1 (top/left) and +1 (right/bottom).
+void mp_get_chroma_location(enum mp_chroma_location loc, int *x, int *y)
+{
+ *x = 0;
+ *y = 0;
+ if (loc == MP_CHROMA_LEFT)
+ *x = -1;
+}
+
/**
* \brief little helper function to create a lookup table for gamma
* \param map buffer to create map into
diff --git a/video/csputils.h b/video/csputils.h
index d11e85e38b..af510299cf 100644
--- a/video/csputils.h
+++ b/video/csputils.h
@@ -87,6 +87,12 @@ struct mp_csp_params {
.rgamma = 1, .ggamma = 1, .bgamma = 1, \
.texture_bits = 8, .input_bits = 8}
+enum mp_chroma_location {
+ MP_CHROMA_AUTO,
+ MP_CHROMA_LEFT, // mpeg2/4, h264
+ MP_CHROMA_CENTER, // mpeg1, jpeg
+};
+
enum mp_csp_equalizer_param {
MP_CSP_EQ_BRIGHTNESS,
MP_CSP_EQ_CONTRAST,
@@ -136,6 +142,10 @@ enum AVColorRange mp_csp_levels_to_avcol_range(enum mp_csp_levels range);
enum mp_csp mp_csp_guess_colorspace(int width, int height);
+enum mp_chroma_location avchroma_location_to_mp(enum AVChromaLocation loc);
+
+void mp_get_chroma_location(enum mp_chroma_location loc, int *x, int *y);
+
void mp_gen_gamma_map(unsigned char *map, int size, float gamma);
#define ROW_R 0
#define ROW_G 1
diff --git a/video/decode/vd_lavc.c b/video/decode/vd_lavc.c
index f67e6dfbe6..ff1565f38f 100644
--- a/video/decode/vd_lavc.c
+++ b/video/decode/vd_lavc.c
@@ -446,6 +446,8 @@ static int init_vo(sh_video_t *sh, AVFrame *frame)
.d_h = height,
.colorspace = avcol_spc_to_mp_csp(ctx->avctx->colorspace),
.colorlevels = avcol_range_to_mp_csp_levels(ctx->avctx->color_range),
+ .chroma_location =
+ avchroma_location_to_mp(ctx->avctx->chroma_sample_location),
};
if (mpcodecs_reconfig_vo(sh, &ctx->image_params) < 0)
@@ -701,6 +703,7 @@ static int decode(struct sh_video *sh, struct demux_packet *packet,
mpi->colorspace = ctx->image_params.colorspace;
mpi->levels = ctx->image_params.colorlevels;
+ mpi->chroma_location = ctx->image_params.chroma_location;
*out_image = mpi;
return 1;
diff --git a/video/filter/vf.c b/video/filter/vf.c
index 26841f380f..0f7cc58ee5 100644
--- a/video/filter/vf.c
+++ b/video/filter/vf.c
@@ -477,6 +477,7 @@ int vf_next_config(struct vf_instance *vf,
.d_h = d_height,
.colorspace = vf->fmt_in.params.colorspace,
.colorlevels = vf->fmt_in.params.colorlevels,
+ .chroma_location = vf->fmt_in.params.chroma_location,
};
int r = vf_reconfig_wrapper(vf->next, &p, voflags);
return r < 0 ? 0 : 1;
diff --git a/video/mp_image.c b/video/mp_image.c
index 85c174dfaa..95b59eae28 100644
--- a/video/mp_image.c
+++ b/video/mp_image.c
@@ -324,6 +324,7 @@ void mp_image_copy_attributes(struct mp_image *dst, struct mp_image *src)
if ((dst->flags & MP_IMGFLAG_YUV) == (src->flags & MP_IMGFLAG_YUV)) {
dst->colorspace = src->colorspace;
dst->levels = src->levels;
+ dst->chroma_location = src->chroma_location;
}
if (dst->imgfmt == IMGFMT_PAL8 && src->imgfmt == IMGFMT_PAL8) {
if (dst->planes[1] && src->planes[1])
diff --git a/video/mp_image.h b/video/mp_image.h
index 643b70b949..96b980039d 100644
--- a/video/mp_image.h
+++ b/video/mp_image.h
@@ -43,6 +43,7 @@ struct mp_image_params {
int d_w, d_h; // define display aspect ratio (never 0/0)
enum mp_csp colorspace;
enum mp_csp_levels colorlevels;
+ enum mp_chroma_location chroma_location;
};
/* Memory management:
@@ -90,6 +91,8 @@ typedef struct mp_image {
enum mp_csp colorspace;
enum mp_csp_levels levels;
+ enum mp_chroma_location chroma_location;
+
/* only inside filter chain */
double pts;
/* memory management */
diff --git a/video/out/gl_video.c b/video/out/gl_video.c
index 658c531546..bdca0a1ff4 100644
--- a/video/out/gl_video.c
+++ b/video/out/gl_video.c
@@ -185,6 +185,7 @@ struct gl_video {
struct mp_csp_details colorspace;
struct mp_csp_equalizer video_eq;
+ enum mp_chroma_location chroma_loc;
struct mp_rect src_rect; // displayed part of the source video
struct mp_rect dst_rect; // video rectangle on output window
@@ -279,6 +280,10 @@ const struct m_sub_options gl_video_conf = {
({"fruit", 0}, {"ordered", 1}, {"no", -1})),
OPT_INTRANGE("dither-size-fruit", dither_size, 0, 2, 8),
OPT_FLAG("temporal-dither", temporal_dither, 0),
+ OPT_CHOICE("chroma-location", chroma_location, 0,
+ ({"auto", MP_CHROMA_AUTO},
+ {"center", MP_CHROMA_CENTER},
+ {"left", MP_CHROMA_LEFT})),
OPT_FLAG("alpha", enable_alpha, 0),
{0}
},
@@ -510,6 +515,27 @@ static void update_uniforms(struct gl_video *p, GLuint program)
p->image.planes[n].tex_w, p->image.planes[n].tex_h);
}
+ loc = gl->GetUniformLocation(program, "chroma_center_offset");
+ if (loc >= 0) {
+ int chr = p->opts.chroma_location;
+ if (!chr)
+ chr = p->chroma_loc;
+ int cx, cy;
+ mp_get_chroma_location(chr, &cx, &cy);
+ // By default texture coordinates are such that chroma is centered with
+ // any chroma subsampling. If a specific direction is given, make it
+ // so that the luma and chroma sample line up exactly.
+ // For 4:4:4, setting chroma location should have no effect at all.
+ // luma sample size (in chroma coord. space)
+ float ls_w = 1.0 / (1 << p->image_desc.chroma_xs);
+ float ls_h = 1.0 / (1 << p->image_desc.chroma_ys);
+ // move chroma center to luma center (in chroma coord. space)
+ float o_x = ls_w < 1 ? ls_w * -cx / 2 : 0;
+ float o_y = ls_h < 1 ? ls_h * -cy / 2 : 0;
+ gl->Uniform2f(loc, o_x / FFMAX(p->image.planes[1].w, 1),
+ o_y / FFMAX(p->image.planes[1].h, 1));
+ }
+
gl->Uniform2f(gl->GetUniformLocation(program, "dither_size"),
p->dither_size, p->dither_size);
@@ -1861,6 +1887,7 @@ void gl_video_config(struct gl_video *p, struct mp_image_params *params)
}
p->image_dw = params->d_w;
p->image_dh = params->d_h;
+ p->chroma_loc = params->chroma_location;
}
void gl_video_set_output_depth(struct gl_video *p, int r, int g, int b)
diff --git a/video/out/gl_video.h b/video/out/gl_video.h
index 289ccddf52..ca0cb5468a 100644
--- a/video/out/gl_video.h
+++ b/video/out/gl_video.h
@@ -45,6 +45,7 @@ struct gl_video_opts {
int fbo_format;
int stereo_mode;
int enable_alpha;
+ int chroma_location;
};
extern const struct m_sub_options gl_video_conf;
diff --git a/video/out/gl_video_shaders.glsl b/video/out/gl_video_shaders.glsl
index 47be240571..6337822c02 100644
--- a/video/out/gl_video_shaders.glsl
+++ b/video/out/gl_video_shaders.glsl
@@ -114,6 +114,7 @@ void main() {
#!section frag_video
uniform sampler2D textures[4];
uniform vec2 textures_size[4];
+uniform vec2 chroma_center_offset;
uniform sampler1D lut_c_1d;
uniform sampler1D lut_l_1d;
uniform sampler2D lut_c_2d;
@@ -321,17 +322,18 @@ vec4 sample_sharpen5(sampler2D tex, vec2 texsize, vec2 texcoord) {
}
void main() {
+ vec2 chr_texcoord = texcoord + chroma_center_offset;
#ifndef USE_CONV
#define USE_CONV 0
#endif
#if USE_CONV == CONV_PLANAR
vec3 color = vec3(SAMPLE_L(textures[0], textures_size[0], texcoord).r,
- SAMPLE_C(textures[1], textures_size[1], texcoord).r,
- SAMPLE_C(textures[2], textures_size[2], texcoord).r);
+ SAMPLE_C(textures[1], textures_size[1], chr_texcoord).r,
+ SAMPLE_C(textures[2], textures_size[2], chr_texcoord).r);
float alpha = 1.0;
#elif USE_CONV == CONV_NV12
vec3 color = vec3(SAMPLE_L(textures[0], textures_size[0], texcoord).r,
- SAMPLE_C(textures[1], textures_size[1], texcoord).rg);
+ SAMPLE_C(textures[1], textures_size[1], chr_texcoord).rg);
float alpha = 1.0;
#else
vec4 acolor = SAMPLE_L(textures[0], textures_size[0], texcoord);