summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--DOCS/tech/slave.txt3
-rw-r--r--cfg-mplayer.h14
-rw-r--r--command.c140
-rw-r--r--input/input.c2
-rw-r--r--libmpcodecs/dec_video.c46
-rw-r--r--libmpcodecs/dec_video.h3
-rw-r--r--libmpcodecs/vd.c3
-rw-r--r--libmpcodecs/vf.h4
-rw-r--r--libmpcodecs/vf_scale.c79
-rw-r--r--libmpcodecs/vf_scale.h3
-rw-r--r--libvo/csputils.c98
-rw-r--r--libvo/csputils.h76
-rw-r--r--libvo/video_out.h6
-rw-r--r--libvo/vo_gl.c121
-rw-r--r--libvo/vo_gl2.c2
-rw-r--r--libvo/vo_vdpau.c91
-rw-r--r--libvo/vo_xv.c14
-rw-r--r--options.h3
18 files changed, 505 insertions, 203 deletions
diff --git a/DOCS/tech/slave.txt b/DOCS/tech/slave.txt
index 0e906cf857..f68d5e9c1b 100644
--- a/DOCS/tech/slave.txt
+++ b/DOCS/tech/slave.txt
@@ -565,6 +565,9 @@ saturation int -100 100 X X X
hue int -100 100 X X X
panscan float 0 1 X X X
vsync flag 0 1 X X X
+colormatrix choice X X X as --colormatrix
+colormatrix_input_range choice X X X as --colormatrix-input-range
+colormatrix_output_range choice X X X as --colormatrix-output-range
video_format int X
video_codec string X
video_bitrate int X
diff --git a/cfg-mplayer.h b/cfg-mplayer.h
index b197854df5..12d4b582c4 100644
--- a/cfg-mplayer.h
+++ b/cfg-mplayer.h
@@ -33,6 +33,7 @@
#include "libmpdemux/demux_ts.h"
#include "stream/tv.h"
#include "stream/stream_radio.h"
+#include "libvo/csputils.h"
extern char *fb_mode_cfgfile;
extern char *fb_mode_name;
@@ -797,6 +798,19 @@ const m_option_t mplayer_opts[]={
{"novsync", &vo_vsync, CONF_TYPE_FLAG, 0, 1, 0, NULL},
{"panscan", &vo_panscan, CONF_TYPE_FLOAT, CONF_RANGE, -1.0, 1.0, NULL},
OPT_FLOATRANGE("panscanrange", vo_panscanrange, 0, -19.0, 99.0),
+ OPT_CHOICE("colormatrix", requested_colorspace, 0,
+ ({"auto", MP_CSP_AUTO}, {"0", MP_CSP_AUTO},
+ {"BT.601", MP_CSP_BT_601}, {"sd", MP_CSP_BT_601}, {"1", MP_CSP_BT_601},
+ {"BT.709", MP_CSP_BT_709}, {"hd", MP_CSP_BT_709}, {"2", MP_CSP_BT_709},
+ {"SMPTE-240M", MP_CSP_SMPTE_240M}, {"3", MP_CSP_SMPTE_240M})),
+ OPT_CHOICE("colormatrix-input-range", requested_input_range, 0,
+ ({"auto", MP_CSP_LEVELS_AUTO},
+ {"limited", MP_CSP_LEVELS_TV},
+ {"full", MP_CSP_LEVELS_PC})),
+ OPT_CHOICE("colormatrix-output-range", requested_output_range, 0,
+ ({"auto", MP_CSP_LEVELS_AUTO},
+ {"limited", MP_CSP_LEVELS_TV},
+ {"full", MP_CSP_LEVELS_PC})),
{"grabpointer", &vo_grabpointer, CONF_TYPE_FLAG, 0, 0, 1, NULL},
{"nograbpointer", &vo_grabpointer, CONF_TYPE_FLAG, 0, 1, 0, NULL},
diff --git a/command.c b/command.c
index e9fc49fd17..789b60186c 100644
--- a/command.c
+++ b/command.c
@@ -41,6 +41,7 @@
#include "libmpcodecs/vd.h"
#include "mp_osd.h"
#include "libvo/video_out.h"
+#include "libvo/csputils.h"
#include "sub/font_load.h"
#include "playtree.h"
#include "libao2/audio_out.h"
@@ -1152,48 +1153,114 @@ static int mp_property_deinterlace(m_option_t *prop, int action,
return m_property_flag_ro(prop, action, arg, value);
}
-static int mp_property_yuv_colorspace(m_option_t *prop, int action,
+static int colormatrix_property_helper(m_option_t *prop, int action,
void *arg, MPContext *mpctx)
{
- if (!mpctx->sh_video || !mpctx->sh_video->vfilter)
- return M_PROPERTY_UNAVAILABLE;
+ int r = mp_property_generic_option(prop, action, arg, mpctx);
+ // testing for an actual change is too much effort
+ switch (action) {
+ case M_PROPERTY_SET:
+ case M_PROPERTY_STEP_UP:
+ case M_PROPERTY_STEP_DOWN:
+ if (mpctx->sh_video)
+ set_video_colorspace(mpctx->sh_video);
+ break;
+ }
+ return r;
+}
- struct vf_instance *vf = mpctx->sh_video->vfilter;
- int colorspace;
+static int mp_property_colormatrix(m_option_t *prop, int action, void *arg,
+ MPContext *mpctx)
+{
+ struct MPOpts *opts = &mpctx->opts;
switch (action) {
- case M_PROPERTY_GET:
- if (!arg)
- return M_PROPERTY_ERROR;
- if (vf->control(vf, VFCTRL_GET_YUV_COLORSPACE, arg) != true)
- return M_PROPERTY_UNAVAILABLE;
- return M_PROPERTY_OK;
case M_PROPERTY_PRINT:
if (!arg)
return M_PROPERTY_ERROR;
- if (vf->control(vf, VFCTRL_GET_YUV_COLORSPACE, &colorspace) != true)
- return M_PROPERTY_UNAVAILABLE;
- char *const names[] = {
- "BT.601 (SD)", "BT.709 (HD)", "SMPTE-240M"
- };
- if (colorspace < 0 || colorspace >= sizeof(names) / sizeof(names[0]))
- *(char **)arg = talloc_strdup(NULL, mp_gtext("unknown"));
- else
- *(char **)arg = talloc_strdup(NULL, names[colorspace]);
+ struct mp_csp_details actual = { .format = -1 };
+ char *req_csp = mp_csp_names[opts->requested_colorspace];
+ char *real_csp = NULL;
+ if (mpctx->sh_video) {
+ struct vf_instance *vf = mpctx->sh_video->vfilter;
+ if (vf->control(vf, VFCTRL_GET_YUV_COLORSPACE, &actual) == true) {
+ real_csp = mp_csp_names[actual.format];
+ } else {
+ real_csp = "Unknown";
+ }
+ }
+ char *res;
+ if (opts->requested_colorspace == MP_CSP_AUTO && real_csp) {
+ // Caveat: doesn't handle the case when the autodetected colorspace
+ // is different from the actual colorspace as used by the
+ // VO - the OSD will display the VO colorspace without
+ // indication that it doesn't match the requested colorspace.
+ res = talloc_asprintf(NULL, "Auto (%s)", real_csp);
+ } else if (opts->requested_colorspace == actual.format || !real_csp) {
+ res = talloc_strdup(NULL, req_csp);
+ } else
+ res = talloc_asprintf(NULL, mp_gtext("%s, but %s used"),
+ req_csp, real_csp);
+ *(char **)arg = res;
return M_PROPERTY_OK;
- case M_PROPERTY_SET:
+ default:;
+ return colormatrix_property_helper(prop, action, arg, mpctx);
+ }
+}
+
+static int levels_property_helper(int offset, m_option_t *prop, int action,
+ void *arg, MPContext *mpctx)
+{
+ char *optname = prop->priv;
+ const struct m_option *opt = m_config_get_option(mpctx->mconfig,
+ bstr(optname));
+ int *valptr = (int *)m_option_get_ptr(opt, &mpctx->opts);
+
+ switch (action) {
+ case M_PROPERTY_PRINT:
if (!arg)
return M_PROPERTY_ERROR;
- M_PROPERTY_CLAMP(prop, *(int *) arg);
- vf->control(vf, VFCTRL_SET_YUV_COLORSPACE, arg);
- return M_PROPERTY_OK;
- case M_PROPERTY_STEP_UP:;
- if (vf->control(vf, VFCTRL_GET_YUV_COLORSPACE, &colorspace) != true)
- return M_PROPERTY_UNAVAILABLE;
- colorspace += 1;
- vf->control(vf, VFCTRL_SET_YUV_COLORSPACE, &colorspace);
+ struct mp_csp_details actual = {0};
+ int actual_level = -1;
+ char *req_level = m_option_print(opt, valptr);
+ char *real_level = NULL;
+ if (mpctx->sh_video) {
+ struct vf_instance *vf = mpctx->sh_video->vfilter;
+ if (vf->control(vf, VFCTRL_GET_YUV_COLORSPACE, &actual) == true) {
+ actual_level = *(enum mp_csp_levels *)(((char *)&actual) + offset);
+ real_level = m_option_print(opt, &actual_level);
+ } else {
+ real_level = talloc_strdup(NULL, "Unknown");
+ }
+ }
+ char *res;
+ if (*valptr == MP_CSP_LEVELS_AUTO && real_level) {
+ res = talloc_asprintf(NULL, "Auto (%s)", real_level);
+ } else if (*valptr == actual_level || !real_level) {
+ res = talloc_strdup(NULL, real_level);
+ } else
+ res = talloc_asprintf(NULL, mp_gtext("%s, but %s used"),
+ req_level, real_level);
+ talloc_free(req_level);
+ talloc_free(real_level);
+ *(char **)arg = res;
return M_PROPERTY_OK;
+ default:;
+ return colormatrix_property_helper(prop, action, arg, mpctx);
}
- return M_PROPERTY_NOT_IMPLEMENTED;
+}
+
+static int mp_property_colormatrix_input_range(m_option_t *prop, int action,
+ void *arg, MPContext *mpctx)
+{
+ return levels_property_helper(offsetof(struct mp_csp_details, levels_in),
+ prop, action, arg, mpctx);
+}
+
+static int mp_property_colormatrix_output_range(m_option_t *prop, int action,
+ void *arg, MPContext *mpctx)
+{
+ return levels_property_helper(offsetof(struct mp_csp_details, levels_out),
+ prop, action, arg, mpctx);
}
static int mp_property_capture(m_option_t *prop, int action,
@@ -2267,8 +2334,12 @@ static const m_option_t mp_properties[] = {
M_OPT_RANGE, 0, 1, NULL },
{ "deinterlace", mp_property_deinterlace, CONF_TYPE_FLAG,
M_OPT_RANGE, 0, 1, NULL },
- { "yuv_colorspace", mp_property_yuv_colorspace, CONF_TYPE_INT,
- M_OPT_RANGE, 0, 2, NULL },
+ { "colormatrix", mp_property_colormatrix, &m_option_type_choice,
+ 0, 0, 0, "colormatrix" },
+ { "colormatrix_input_range", mp_property_colormatrix_input_range, &m_option_type_choice,
+ 0, 0, 0, "colormatrix-input-range" },
+ { "colormatrix_output_range", mp_property_colormatrix_output_range, &m_option_type_choice,
+ 0, 0, 0, "colormatrix-output-range" },
{ "ontop", mp_property_ontop, CONF_TYPE_FLAG,
M_OPT_RANGE, 0, 1, NULL },
{ "rootwin", mp_property_rootwin, CONF_TYPE_FLAG,
@@ -2430,7 +2501,9 @@ static struct property_osd_display {
{ "border", 0, -1, _("Border: %s") },
{ "framedropping", 0, -1, _("Framedropping: %s") },
{ "deinterlace", 0, -1, _("Deinterlace: %s") },
- { "yuv_colorspace", 0, -1, _("YUV colorspace: %s") },
+ { "colormatrix", 0, -1, _("YUV colormatrix: %s") },
+ { "colormatrix_input_range", 0, -1, _("YUV input range: %s") },
+ { "colormatrix_output_range", 0, -1, _("RGB output range: %s") },
{ "gamma", OSD_BRIGHTNESS, -1, _("Gamma") },
{ "brightness", OSD_BRIGHTNESS, -1, _("Brightness") },
{ "contrast", OSD_CONTRAST, -1, _("Contrast") },
@@ -2473,6 +2546,7 @@ static int show_property_osd(MPContext *mpctx, const char *pname)
for (p = property_osd_display; p->name; p++)
if (!strcmp(p->name, pname))
break;
+
if (!p->name)
return -1;
diff --git a/input/input.c b/input/input.c
index 35714820e3..29b462a49f 100644
--- a/input/input.c
+++ b/input/input.c
@@ -467,7 +467,7 @@ static const struct cmd_bind def_cmd_binds[] = {
{ { '8', 0 }, "saturation 1" },
{ { 'd', 0 }, "frame_drop" },
{ { 'D', 0 }, "step_property_osd deinterlace" },
- { { 'c', 0 }, "step_property_osd yuv_colorspace" },
+ { { 'c', 0 }, "step_property_osd colormatrix" },
{ { 'r', 0 }, "sub_pos -1" },
{ { 't', 0 }, "sub_pos +1" },
{ { 'a', 0 }, "sub_alignment" },
diff --git a/libmpcodecs/dec_video.c b/libmpcodecs/dec_video.c
index 8dbd733fd7..b41e4fb768 100644
--- a/libmpcodecs/dec_video.c
+++ b/libmpcodecs/dec_video.c
@@ -36,6 +36,7 @@
#include "codec-cfg.h"
#include "libvo/video_out.h"
+#include "libvo/csputils.h"
#include "libmpdemux/stheader.h"
#include "vd.h"
@@ -139,6 +140,51 @@ int get_video_colors(sh_video_t *sh_video, const char *item, int *value)
return 0;
}
+void get_detected_video_colorspace(struct sh_video *sh, struct mp_csp_details *csp)
+{
+ struct MPOpts *opts = sh->opts;
+ struct vf_instance *vf = sh->vfilter;
+
+ csp->format = opts->requested_colorspace;
+ csp->levels_in = opts->requested_input_range;
+ csp->levels_out = opts->requested_output_range;
+
+ if (csp->format == MP_CSP_AUTO)
+ csp->format = mp_csp_guess_colorspace(vf->w, vf->h);
+ if (csp->levels_in == MP_CSP_LEVELS_AUTO)
+ csp->levels_in = MP_CSP_LEVELS_TV;
+ if (csp->levels_out == MP_CSP_LEVELS_AUTO)
+ csp->levels_out = MP_CSP_LEVELS_PC;
+}
+
+void set_video_colorspace(struct sh_video *sh)
+{
+ struct vf_instance *vf = sh->vfilter;
+
+ struct mp_csp_details requested;
+ get_detected_video_colorspace(sh, &requested);
+ vf->control(vf, VFCTRL_SET_YUV_COLORSPACE, &requested);
+
+ struct mp_csp_details actual = MP_CSP_DETAILS_DEFAULTS;
+ vf->control(vf, VFCTRL_GET_YUV_COLORSPACE, &actual);
+
+ int success = actual.format == requested.format
+ && actual.levels_in == requested.levels_in
+ && actual.levels_out == requested.levels_out;
+
+ if (!success)
+ mp_tmsg(MSGT_DECVIDEO, MSGL_WARN,
+ "Colorspace details not fully supported by selected vo.\n");
+
+ if (actual.format != requested.format
+ && requested.format == MP_CSP_SMPTE_240M) {
+ // BT.709 is pretty close, much better than BT.601
+ requested.format = MP_CSP_BT_709;
+ vf->control(vf, VFCTRL_SET_YUV_COLORSPACE, &requested);
+ }
+
+}
+
int set_rectangle(sh_video_t *sh_video, int param, int value)
{
vf_instance_t *vf = sh_video->vfilter;
diff --git a/libmpcodecs/dec_video.h b/libmpcodecs/dec_video.h
index be087d09b9..60a9e5f2d2 100644
--- a/libmpcodecs/dec_video.h
+++ b/libmpcodecs/dec_video.h
@@ -40,6 +40,9 @@ void set_video_quality(sh_video_t *sh_video, int quality);
int get_video_colors(sh_video_t *sh_video, const char *item, int *value);
int set_video_colors(sh_video_t *sh_video, const char *item, int value);
+struct mp_csp_details;
+void get_detected_video_colorspace(struct sh_video *sh, struct mp_csp_details *csp);
+void set_video_colorspace(struct sh_video *sh);
int set_rectangle(sh_video_t *sh_video, int param, int value);
int redraw_osd(struct sh_video *sh_video, struct osd_state *osd);
void resync_video_stream(sh_video_t *sh_video);
diff --git a/libmpcodecs/vd.c b/libmpcodecs/vd.c
index 3ba72790a5..21c940b9be 100644
--- a/libmpcodecs/vd.c
+++ b/libmpcodecs/vd.c
@@ -327,6 +327,7 @@ int mpcodecs_config_vo2(sh_video_t *sh, int w, int h,
vf->w = sh->disp_w;
vf->h = sh->disp_h;
+
if (vf_config_wrapper
(vf, sh->disp_w, sh->disp_h, screen_size_x, screen_size_y, vocfg_flags,
out_fmt) == 0) {
@@ -337,6 +338,8 @@ int mpcodecs_config_vo2(sh_video_t *sh, int w, int h,
sh->vf_initialized = 1;
+ set_video_colorspace(sh);
+
if (opts->vo_gamma_gamma != 1000)
set_video_colors(sh, "gamma", opts->vo_gamma_gamma);
if (opts->vo_gamma_brightness != 1000)
diff --git a/libmpcodecs/vf.h b/libmpcodecs/vf.h
index ec1a9c23ff..11ee5eaf8e 100644
--- a/libmpcodecs/vf.h
+++ b/libmpcodecs/vf.h
@@ -113,8 +113,8 @@ typedef struct vf_seteq_s
* access OSD/subtitle state outside of normal OSD draw time. */
#define VFCTRL_SET_OSD_OBJ 20
#define VFCTRL_REDRAW_OSD 21 /* Change user-visible OSD immediately */
-#define VFCTRL_SET_YUV_COLORSPACE 22
-#define VFCTRL_GET_YUV_COLORSPACE 23
+#define VFCTRL_SET_YUV_COLORSPACE 22 /* arg is struct mp_csp_details* */
+#define VFCTRL_GET_YUV_COLORSPACE 23 /* arg is struct mp_csp_details* */
#include "vfcap.h"
diff --git a/libmpcodecs/vf_scale.c b/libmpcodecs/vf_scale.c
index 1a2cb28e94..8cd0a37c33 100644
--- a/libmpcodecs/vf_scale.c
+++ b/libmpcodecs/vf_scale.c
@@ -35,6 +35,8 @@
#include "libswscale/swscale.h"
#include "vf_scale.h"
+#include "libvo/csputils.h"
+
#include "m_option.h"
#include "m_struct.h"
@@ -49,6 +51,7 @@ static struct vf_priv_s {
int interlaced;
int noup;
int accurate_rnd;
+ struct mp_csp_details colorspace;
} const vf_priv_dflt = {
-1,-1,
0,
@@ -187,6 +190,8 @@ static int config(struct vf_instance *vf,
SwsFilter *srcFilter, *dstFilter;
enum PixelFormat dfmt, sfmt;
+ vf->priv->colorspace = (struct mp_csp_details) {0};
+
if(!best){
mp_msg(MSGT_VFILTER,MSGL_WARN,"SwScale: no supported outfmt found :(\n");
return 0;
@@ -505,6 +510,32 @@ static int control(struct vf_instance *vf, int request, void* data){
}
return CONTROL_TRUE;
+ case VFCTRL_SET_YUV_COLORSPACE: {
+ struct mp_csp_details colorspace = *(struct mp_csp_details *)data;
+ if (mp_sws_set_colorspace(vf->priv->ctx, &colorspace) >= 0) {
+ if (vf->priv->ctx2)
+ mp_sws_set_colorspace(vf->priv->ctx2, &colorspace);
+ vf->priv->colorspace = colorspace;
+ return 1;
+ }
+ break;
+ }
+ case VFCTRL_GET_YUV_COLORSPACE: {
+ /* This scale filter should never react to colorspace commands if it
+ * doesn't do YUV->RGB conversion. But because finding out whether this
+ * is really YUV->RGB (and not YUV->YUV or anything else) is hard,
+ * react only if the colorspace has been set explicitly before. The
+ * trick is that mp_sws_set_colorspace does not succeed for YUV->YUV
+ * and RGB->YUV conversions, which makes this code correct in "most"
+ * cases. (This would be trivial to do correctly if libswscale exposed
+ * functionality like isYUV()).
+ */
+ if (vf->priv->colorspace.format) {
+ *(struct mp_csp_details *)data = vf->priv->colorspace;
+ return CONTROL_TRUE;
+ }
+ break;
+ }
default:
break;
}
@@ -512,6 +543,54 @@ static int control(struct vf_instance *vf, int request, void* data){
return vf_next_control(vf,request,data);
}
+static const int mp_csp_to_swscale[MP_CSP_COUNT] = {
+ [MP_CSP_BT_601] = SWS_CS_ITU601,
+ [MP_CSP_BT_709] = SWS_CS_ITU709,
+ [MP_CSP_SMPTE_240M] = SWS_CS_SMPTE240M,
+};
+
+// Adjust the colorspace used for YUV->RGB conversion. On other conversions,
+// do nothing or return an error.
+// The csp argument is set to the supported values.
+// Return 0 on success and -1 on error.
+int mp_sws_set_colorspace(struct SwsContext *sws, struct mp_csp_details *csp)
+{
+ int *table, *inv_table;
+ int brightness, contrast, saturation, srcRange, dstRange;
+
+ csp->levels_out = MP_CSP_LEVELS_PC;
+
+ // NOTE: returns an error if the destination format is YUV
+ if (sws_getColorspaceDetails(sws, &inv_table, &srcRange, &table, &dstRange,
+ &brightness, &contrast, &saturation) == -1)
+ goto error_out;
+
+ int sws_csp = mp_csp_to_swscale[csp->format];
+ if (sws_csp == 0) {
+ // colorspace not supported, go with a reasonable default
+ csp->format = SWS_CS_ITU601;
+ sws_csp = MP_CSP_BT_601;
+ }
+
+ /* The swscale API for these is hardly documented.
+ * Apparently table/range only apply to YUV. Thus dstRange has no effect
+ * for YUV->RGB conversions, and conversions to limited-range RGB are
+ * not supported.
+ */
+ srcRange = csp->levels_in == MP_CSP_LEVELS_PC;
+ const int *new_inv_table = sws_getCoefficients(sws_csp);
+
+ if (sws_setColorspaceDetails(sws, new_inv_table, srcRange, table, dstRange,
+ brightness, contrast, saturation) == -1)
+ goto error_out;
+
+ return 0;
+
+error_out:
+ *csp = (struct mp_csp_details){0};
+ return -1;
+}
+
//===========================================================================//
// supported Input formats: YV12, I420, IYUV, YUY2, UYVY, BGR32, BGR24, BGR16, BGR15, RGB32, RGB24, Y8, Y800
diff --git a/libmpcodecs/vf_scale.h b/libmpcodecs/vf_scale.h
index 359ed2c4f8..a9b3b506d5 100644
--- a/libmpcodecs/vf_scale.h
+++ b/libmpcodecs/vf_scale.h
@@ -22,4 +22,7 @@
int get_sws_cpuflags(void);
struct SwsContext *sws_getContextFromCmdLine(int srcW, int srcH, int srcFormat, int dstW, int dstH, int dstFormat);
+struct mp_csp_details;
+int mp_sws_set_colorspace(struct SwsContext *sws, struct mp_csp_details *csp);
+
#endif /* MPLAYER_VF_SCALE_H */
diff --git a/libvo/csputils.c b/libvo/csputils.c
index 831e5c774a..6656e5e196 100644
--- a/libvo/csputils.c
+++ b/libvo/csputils.c
@@ -32,6 +32,27 @@
#include "csputils.h"
+char * const mp_csp_names[MP_CSP_COUNT] = {
+ "Autoselect",
+ "BT.601 (SD)",
+ "BT.709 (HD)",
+ "SMPTE-240M",
+};
+
+char * const mp_csp_equalizer_names[MP_CSP_EQ_COUNT] = {
+ "brightness",
+ "contrast",
+ "hue",
+ "saturation",
+ "gamma",
+};
+
+
+enum mp_csp mp_csp_guess_colorspace(int width, int height)
+{
+ return width >= 1280 || height > 576 ? MP_CSP_BT_709 : MP_CSP_BT_601;
+}
+
/**
* \brief little helper function to create a lookup table for gamma
* \param map buffer to create map into
@@ -98,8 +119,8 @@ static void luma_coeffs(float m[3][4], float lr, float lg, float lb)
*/
void mp_get_yuv2rgb_coeffs(struct mp_csp_params *params, float m[3][4])
{
- int format = params->format;
- if (format <= MP_CSP_DEFAULT || format >= MP_CSP_COUNT)
+ int format = params->colorspace.format;
+ if (format <= MP_CSP_AUTO || format >= MP_CSP_COUNT)
format = MP_CSP_BT_601;
switch (format) {
case MP_CSP_BT_601: luma_coeffs(m, 0.299, 0.587, 0.114 ); break;
@@ -119,25 +140,35 @@ void mp_get_yuv2rgb_coeffs(struct mp_csp_params *params, float m[3][4])
m[i][COL_V] = huesin * u + huecos * m[i][COL_V];
}
- int levelconv = params->levelconv;
- if (levelconv < 0 || levelconv >= MP_CSP_LEVELCONV_COUNT)
- levelconv = MP_CSP_LEVELCONV_TV_TO_PC;
+ int levels_in = params->colorspace.levels_in;
+ if (levels_in <= MP_CSP_LEVELS_AUTO || levels_in >= MP_CSP_LEVELS_COUNT)
+ levels_in = MP_CSP_LEVELS_TV;
// The values below are written in 0-255 scale
struct yuvlevels { double ymin, ymax, cmin, cmid; }
yuvlim = { 16, 235, 16, 128 },
- yuvfull = { 16, 235, 1, 128 }, // '1' to make it symmetric around 128
+ yuvfull = { 0, 255, 1, 128 }, // '1' to make it symmetric around 128
yuvlev;
+ switch (levels_in) {
+ case MP_CSP_LEVELS_TV: yuvlev = yuvlim; break;
+ case MP_CSP_LEVELS_PC: yuvlev = yuvfull; break;
+ default:
+ abort();
+ }
+
+ int levels_out = params->colorspace.levels_out;
+ if (levels_out <= MP_CSP_LEVELS_AUTO || levels_out >= MP_CSP_LEVELS_COUNT)
+ levels_out = MP_CSP_LEVELS_PC;
struct rgblevels { double min, max; }
rgblim = { 16, 235 },
rgbfull = { 0, 255 },
rgblev;
- switch (levelconv) {
- case MP_CSP_LEVELCONV_TV_TO_PC: yuvlev = yuvlim; rgblev = rgbfull; break;
- case MP_CSP_LEVELCONV_PC_TO_TV: yuvlev = yuvfull; rgblev = rgblim; break;
- case MP_CSP_LEVELCONV_TV_TO_TV: yuvlev = yuvlim; rgblev = rgblim; break;
+ switch (levels_out) {
+ case MP_CSP_LEVELS_TV: rgblev = rgblim; break;
+ case MP_CSP_LEVELS_PC: rgblev = rgbfull; break;
default:
abort();
}
+
double ymul = (rgblev.max - rgblev.min) / (yuvlev.ymax - yuvlev.ymin);
double cmul = (rgblev.max - rgblev.min) / (yuvlev.cmid - yuvlev.cmin) / 2;
for (int i = 0; i < 3; i++) {
@@ -205,3 +236,50 @@ void mp_gen_yuv2rgb_map(struct mp_csp_params *params, unsigned char *map, int si
v += (i == -1 || i == size - 1) ? step / 2 : step;
}
}
+
+// Copy settings from eq into params.
+void mp_csp_copy_equalizer_values(struct mp_csp_params *params,
+ const struct mp_csp_equalizer *eq)
+{
+ params->brightness = eq->values[MP_CSP_EQ_BRIGHTNESS] / 100.0;
+ params->contrast = (eq->values[MP_CSP_EQ_CONTRAST] + 100) / 100.0;
+ params->hue = eq->values[MP_CSP_EQ_HUE] / 100.0 * 3.1415927;
+ params->saturation = (eq->values[MP_CSP_EQ_SATURATION] + 100) / 100.0;
+ float gamma = exp(log(8.0) * eq->values[MP_CSP_EQ_GAMMA] / 100.0);
+ params->rgamma = gamma;
+ params->ggamma = gamma;
+ params->bgamma = gamma;
+}
+
+static int find_eq(int capabilities, const char *name)
+{
+ for (int i = 0; i < MP_CSP_EQ_COUNT; i++) {
+ if (strcmp(name, mp_csp_equalizer_names[i]) == 0)
+ return ((1 << i) & capabilities) ? i : -1;
+ }
+ return -1;
+}
+
+int mp_csp_equalizer_get(struct mp_csp_equalizer *eq, const char *property,
+ int *out_value)
+{
+ int index = find_eq(eq->capabilities, property);
+ if (index < 0)
+ return -1;
+
+ *out_value = eq->values[index];
+
+ return 0;
+}
+
+int mp_csp_equalizer_set(struct mp_csp_equalizer *eq, const char *property,
+ int value)
+{
+ int index = find_eq(eq->capabilities, property);
+ if (index < 0)
+ return 0;
+
+ eq->values[index] = value;
+
+ return 1;
+}
diff --git a/libvo/csputils.h b/libvo/csputils.h
index 93f9ca0316..3a754a8273 100644
--- a/libvo/csputils.h
+++ b/libvo/csputils.h
@@ -26,24 +26,41 @@
#include <stdint.h>
-enum mp_csp_standard {
- MP_CSP_DEFAULT,
+
+/* NOTE: the csp and levels AUTO values are converted to specific ones
+ * above vf/vo level. At least vf_scale relies on all valid settings being
+ * nonzero at vf/vo level.
+ */
+
+enum mp_csp {
+ MP_CSP_AUTO,
MP_CSP_BT_601,
MP_CSP_BT_709,
MP_CSP_SMPTE_240M,
MP_CSP_COUNT
};
-enum mp_csp_levelconv {
- MP_CSP_LEVELCONV_TV_TO_PC,
- MP_CSP_LEVELCONV_PC_TO_TV,
- MP_CSP_LEVELCONV_TV_TO_TV,
- MP_CSP_LEVELCONV_COUNT
+// Any enum mp_csp value is a valid index (except MP_CSP_COUNT)
+extern char * const mp_csp_names[MP_CSP_COUNT];
+
+enum mp_csp_levels {
+ MP_CSP_LEVELS_AUTO,
+ MP_CSP_LEVELS_TV,
+ MP_CSP_LEVELS_PC,
+ MP_CSP_LEVELS_COUNT,
+};
+
+struct mp_csp_details {
+ enum mp_csp format;
+ enum mp_csp_levels levels_in; // encoded video
+ enum mp_csp_levels levels_out; // output device
};
+// initializer for struct mp_csp_details that contains reasonable defaults
+#define MP_CSP_DETAILS_DEFAULTS {MP_CSP_BT_601, MP_CSP_LEVELS_TV, MP_CSP_LEVELS_PC}
+
struct mp_csp_params {
- enum mp_csp_standard format;
- enum mp_csp_levelconv levelconv;
+ struct mp_csp_details colorspace;
float brightness;
float contrast;
float hue;
@@ -54,6 +71,47 @@ struct mp_csp_params {
int input_shift;
};
+enum mp_csp_equalizer_param {
+ MP_CSP_EQ_BRIGHTNESS,
+ MP_CSP_EQ_CONTRAST,
+ MP_CSP_EQ_HUE,
+ MP_CSP_EQ_SATURATION,
+ MP_CSP_EQ_GAMMA,
+ MP_CSP_EQ_COUNT,
+};
+
+#define MP_CSP_EQ_CAPS_COLORMATRIX \
+ ( (1 << MP_CSP_EQ_BRIGHTNESS) \
+ | (1 << MP_CSP_EQ_CONTRAST) \
+ | (1 << MP_CSP_EQ_HUE) \
+ | (1 << MP_CSP_EQ_SATURATION) )
+
+#define MP_CSP_EQ_CAPS_GAMMA (1 << MP_CSP_EQ_GAMMA)
+
+extern char * const mp_csp_equalizer_names[MP_CSP_EQ_COUNT];
+
+// Default initialization with 0 is enough, except for the capabilities field
+struct mp_csp_equalizer {
+ // Bit field of capabilities. For example (1 << MP_CSP_EQ_HUE) means hue
+ // support is available.
+ int capabilities;
+ // Value for each property is in the range [-100, 100].
+ // 0 is default, meaning neutral or no change.
+ int values[MP_CSP_EQ_COUNT];
+};
+
+
+void mp_csp_copy_equalizer_values(struct mp_csp_params *params,
+ const struct mp_csp_equalizer *eq);
+
+int mp_csp_equalizer_set(struct mp_csp_equalizer *eq, const char *property,
+ int value);
+
+int mp_csp_equalizer_get(struct mp_csp_equalizer *eq, const char *property,
+ int *out_value);
+
+enum mp_csp mp_csp_guess_colorspace(int width, int height);
+
void mp_gen_gamma_map(unsigned char *map, int size, float gamma);
#define ROW_R 0
#define ROW_G 1
diff --git a/libvo/video_out.h b/libvo/video_out.h
index ca249819ff..d1a2a7f65a 100644
--- a/libvo/video_out.h
+++ b/libvo/video_out.h
@@ -76,8 +76,8 @@ enum mp_voctrl {
VOCTRL_UPDATE_SCREENINFO,
- VOCTRL_SET_YUV_COLORSPACE,
- VOCTRL_GET_YUV_COLORSPACE,
+ VOCTRL_SET_YUV_COLORSPACE, // struct mp_csp_details
+ VOCTRL_GET_YUV_COLORSPACE, // struct mp_csp_details
};
// VOCTRL_SET_EQUALIZER
@@ -98,7 +98,7 @@ typedef struct {
uint16_t r,g,b;
} mp_colorkey_t;
-//VOCTRL_GET_EOSD_RES
+// VOCTRL_GET_EOSD_RES
typedef struct mp_eosd_res {
int w, h; // screen dimensions, including black borders
int mt, mb, ml, mr; // borders (top, bottom, left, right)
diff --git a/libvo/vo_gl.c b/libvo/vo_gl.c
index cefa30cba3..cb1ccc593b 100644
--- a/libvo/vo_gl.c
+++ b/libvo/vo_gl.c
@@ -25,6 +25,7 @@
#include <stdlib.h>
#include <string.h>
#include <math.h>
+#include <stdbool.h>
#include "config.h"
#include "mp_msg.h"
@@ -129,8 +130,9 @@ static int use_ycbcr;
#define MASK_NOT_COMBINERS (~((1 << YUV_CONVERSION_NONE) | (1 << YUV_CONVERSION_COMBINERS)))
#define MASK_GAMMA_SUPPORT (MASK_NOT_COMBINERS & ~(1 << YUV_CONVERSION_FRAGMENT))
static int use_yuv;
-static int colorspace;
-static int levelconv;
+static struct mp_csp_details colorspace = MP_CSP_DETAILS_DEFAULTS;
+static int user_colorspace; //essentially unused; legacy warning
+static int levelconv; //essentially unused; legacy warning
static int is_yuv;
static int lscale;
static int cscale;
@@ -169,13 +171,8 @@ static int mipmap_gen;
static int stereo_mode;
static int int_pause;
-static int eq_bri = 0;
-static int eq_cont = 0;
-static int eq_sat = 0;
-static int eq_hue = 0;
-static int eq_rgamma = 0;
-static int eq_ggamma = 0;
-static int eq_bgamma = 0;
+
+static struct mp_csp_equalizer video_eq;
static int texture_width;
static int texture_height;
@@ -248,15 +245,9 @@ static void texSize(int w, int h, int *texw, int *texh) {
#define MAX_CUSTOM_PROG_SIZE (1024 * 1024)
static void update_yuvconv(void) {
int xs, ys, depth;
- float bri = eq_bri / 100.0;
- float cont = (eq_cont + 100) / 100.0;
- float hue = eq_hue / 100.0 * 3.1415927;
- float sat = (eq_sat + 100) / 100.0;
- float rgamma = exp(log(8.0) * eq_rgamma / 100.0);
- float ggamma = exp(log(8.0) * eq_ggamma / 100.0);
- float bgamma = exp(log(8.0) * eq_bgamma / 100.0);
- gl_conversion_params_t params = {gl_target, yuvconvtype,
- {colorspace, levelconv, bri, cont, hue, sat, rgamma, ggamma, bgamma, 0},
+ struct mp_csp_params cparams = { .colorspace = colorspace };
+ mp_csp_copy_equalizer_values(&cparams, &video_eq);
+ gl_conversion_params_t params = {gl_target, yuvconvtype, cparams,
texture_width, texture_height, 0, 0, filter_strength};
mp_get_chroma_shift(image_format, &xs, &ys, &depth);
params.chrom_texw = params.texw >> xs;
@@ -521,6 +512,19 @@ static void autodetectGlExtensions(void) {
use_osd = mpglBindTexture != NULL;
if (use_yuv == -1)
use_yuv = glAutodetectYUVConversion();
+
+ int eq_caps = 0;
+ int yuv_mask = (1 << use_yuv);
+ if (!(yuv_mask & MASK_NOT_COMBINERS)) {
+ // combiners
+ eq_caps = (1 << MP_CSP_EQ_HUE) | (1 << MP_CSP_EQ_SATURATION);
+ } else if (yuv_mask & MASK_ALL_YUV) {
+ eq_caps = MP_CSP_EQ_CAPS_COLORMATRIX;
+ if (yuv_mask & MASK_GAMMA_SUPPORT)
+ eq_caps |= MP_CSP_EQ_CAPS_GAMMA;
+ }
+ video_eq.capabilities = eq_caps;
+
if (is_ati && (lscale == 1 || lscale == 2 || cscale == 1 || cscale == 2))
mp_msg(MSGT_VO, MSGL_WARN, "[gl] Selected scaling mode may be broken on ATI cards.\n"
"Tell _them_ to fix GL_REPEAT if you have issues.\n");
@@ -1133,18 +1137,6 @@ uninit(void)
uninit_mpglcontext(&glctx);
}
-static int valid_csp(void *p)
-{
- int *csp = p;
- return *csp >= -1 && *csp < MP_CSP_COUNT;
-}
-
-static int valid_csp_lvl(void *p)
-{
- int *lvl = p;
- return *lvl >= -1 && *lvl < MP_CSP_LEVELCONV_COUNT;
-}
-
static const opt_t subopts[] = {
{"manyfmts", OPT_ARG_BOOL, &many_fmts,