From 98ee8dd15976501157c894ec385c4c551c6614ad Mon Sep 17 00:00:00 2001 From: Uoti Urpala Date: Sun, 15 Nov 2009 15:21:40 +0200 Subject: Add yuv_colorspace property, implemented in vo_vdpau and vo_xv MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a property to select YUV colorspace. Currently implemented only in vo_vdpau and vo_xv. Allows switching between BT.601, BT.709 and SMPTE-240M (vdpau only). The xv support uses the "XV_ITURBT_709" attribute. At least my NVIDIA card supports that; I don't know whether other xv implementations do. Bind the colorspace switch to the 'c' key by default. 'c' is currently used by vo_sdl for some fullscreen mode change thing, but at the moment that does not conflict and if it will in the future then vo_sdl can change. VDPAU part based on a patch from Lauri Mylläri --- DOCS/man/en/mplayer.1 | 22 ++++++++++++++++++- command.c | 45 +++++++++++++++++++++++++++++++++++++++ input/input.c | 1 + libmpcodecs/vf.h | 2 ++ libmpcodecs/vf_vo.c | 4 ++++ libvo/video_out.h | 3 +++ libvo/vo_vdpau.c | 59 +++++++++++++++++++++++++++++++++++++++------------ libvo/vo_xv.c | 9 ++++++++ libvo/x11_common.c | 8 ++++++- 9 files changed, 137 insertions(+), 16 deletions(-) diff --git a/DOCS/man/en/mplayer.1 b/DOCS/man/en/mplayer.1 index 6c832c0217..b48f653892 100644 --- a/DOCS/man/en/mplayer.1 +++ b/DOCS/man/en/mplayer.1 @@ -282,8 +282,10 @@ Show filename on the OSD. Seek to the beginning of the previous/next chapter. .IPs "D (\-vo xvmc, \-vo vdpau, \-vf yadif, \-vf kerndeint only)" Activate/deactivate deinterlacer. -.IPs "A" +.IPs "A\ \ \ \ " Cycle through the available DVD angles. +.IPs "c (currently -vo vdpau and -vo xv only)" +Change YUV colorspace. .RE .PD 1 .PP @@ -3442,6 +3444,24 @@ Use nochroma\-deint to solely use luma and speed up advanced deinterlacing. Useful with slow video memory. .IPs pullup Try to apply inverse telecine, needs motion adaptive temporal deinterlacing. +.IPs colorspace +Select the color space for YUV to RGB conversion (default: 1, BT.601). +In general BT.601 should be used for standard definition (SD) content and +BT.709 for high definition (HD) content. +Using incorrect color space results in slightly under or over saturated and +shifted colors. +.RSss +.IPs 0 +Guess the color space based on video resolution. +Video with width >= 1280 or height > 576 is assumed to be HD and BT.709 color +space will be used. +.IPs 1 +Use ITU-R BT.601 color space (default). +.IPs 2 +Use ITU-R BT.709 color space. +.IPs 3 +Use SMPTE-240M color space. +.RE .IPs fps= Override autodetected display refresh rate value (the value is needed for framedrop to allow video playback rates higher than display refresh rate, and for vsync-aware frame timing adjustments). Default 0 means use autodetected value. diff --git a/command.c b/command.c index 9738377dd3..b52cfaf07d 100644 --- a/command.c +++ b/command.c @@ -1051,6 +1051,48 @@ 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, + void *arg, MPContext *mpctx) +{ + if (!mpctx->sh_video || !mpctx->sh_video->vfilter) + return M_PROPERTY_UNAVAILABLE; + + struct vf_instance *vf = mpctx->sh_video->vfilter; + int colorspace; + 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 = strdup("Unknown"); + else + *(char**)arg = strdup(names[colorspace]); + return M_PROPERTY_OK; + case M_PROPERTY_SET: + 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); + return M_PROPERTY_OK; + } + return M_PROPERTY_NOT_IMPLEMENTED; +} + /// Panscan (RW) static int mp_property_panscan(m_option_t *prop, int action, void *arg, MPContext *mpctx) @@ -2058,6 +2100,8 @@ 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 }, { "ontop", mp_property_ontop, CONF_TYPE_FLAG, M_OPT_RANGE, 0, 1, NULL }, { "rootwin", mp_property_rootwin, CONF_TYPE_FLAG, @@ -2217,6 +2261,7 @@ 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") }, { "gamma", OSD_BRIGHTNESS, -1, _("Gamma") }, { "brightness", OSD_BRIGHTNESS, -1, _("Brightness") }, { "contrast", OSD_CONTRAST, -1, _("Contrast") }, diff --git a/input/input.c b/input/input.c index 71dfb38155..7738da8bcf 100644 --- a/input/input.c +++ b/input/input.c @@ -426,6 +426,7 @@ static const mp_cmd_bind_t def_cmd_binds[] = { { { '8', 0 }, "saturation 1" }, { { 'd', 0 }, "frame_drop" }, { { 'D', 0 }, "step_property_osd deinterlace" }, + { { 'c', 0 }, "step_property_osd yuv_colorspace" }, { { 'r', 0 }, "sub_pos -1" }, { { 't', 0 }, "sub_pos +1" }, { { 'a', 0 }, "sub_alignment" }, diff --git a/libmpcodecs/vf.h b/libmpcodecs/vf.h index d0e3c1cba4..f9dbb8b4fb 100644 --- a/libmpcodecs/vf.h +++ b/libmpcodecs/vf.h @@ -93,6 +93,8 @@ typedef struct vf_seteq_s * the OSD 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 #include "vfcap.h" diff --git a/libmpcodecs/vf_vo.c b/libmpcodecs/vf_vo.c index 7416e5f1d4..7026ac93fc 100644 --- a/libmpcodecs/vf_vo.c +++ b/libmpcodecs/vf_vo.c @@ -88,6 +88,10 @@ static int control(struct vf_instance* vf, int request, void* data) if(!video_out) return CONTROL_FALSE; // vo not configured? return vo_control(video_out, VOCTRL_SET_DEINTERLACE, data) == VO_TRUE; } + case VFCTRL_GET_YUV_COLORSPACE: + return vo_control(video_out, VOCTRL_GET_YUV_COLORSPACE, data) == true; + case VFCTRL_SET_YUV_COLORSPACE: + return vo_control(video_out, VOCTRL_SET_YUV_COLORSPACE, data) == true; case VFCTRL_DRAW_OSD: if(!video_out->config_ok) return CONTROL_FALSE; // vo not configured? vo_draw_osd(video_out, data); diff --git a/libvo/video_out.h b/libvo/video_out.h index 50602e83a4..17c387a320 100644 --- a/libvo/video_out.h +++ b/libvo/video_out.h @@ -88,6 +88,9 @@ typedef struct { #define VOCTRL_UPDATE_SCREENINFO 32 +#define VOCTRL_SET_YUV_COLORSPACE 33 +#define VOCTRL_GET_YUV_COLORSPACE 34 + // Vo can be used by xover #define VOCTRL_XOVERLAY_SUPPORT 22 diff --git a/libvo/vo_vdpau.c b/libvo/vo_vdpau.c index 6eef93842f..a228b00787 100644 --- a/libvo/vo_vdpau.c +++ b/libvo/vo_vdpau.c @@ -124,6 +124,8 @@ struct vdpctx { int output_surface_width, output_surface_height; VdpVideoMixer video_mixer; + int user_colorspace; + int colorspace; int deint; int deint_type; int deint_counter; @@ -541,6 +543,33 @@ static int win_x11_init_vdpau_flip_queue(struct vo *vo) return 0; } +static void update_csc_matrix(struct vo *vo) +{ + struct vdpctx *vc = vo->priv; + struct vdp_functions *vdp = vc->vdp; + VdpStatus vdp_st; + + const VdpColorStandard vdp_colors[] = {VDP_COLOR_STANDARD_ITUR_BT_601, + VDP_COLOR_STANDARD_ITUR_BT_709, + VDP_COLOR_STANDARD_SMPTE_240M}; + char * const vdp_names[] = {"BT.601", "BT.709", "SMPTE-240M"}; + int csp = vc->colorspace; + mp_msg(MSGT_VO, MSGL_V, "[vdpau] Updating CSC matrix for %s\n", + vdp_names[csp]); + + VdpCSCMatrix matrix; + vdp_st = vdp->generate_csc_matrix(&vc->procamp, vdp_colors[csp], &matrix); + CHECK_ST_WARNING("Error when generating CSC matrix"); + + const VdpVideoMixerAttribute attributes[] = + {VDP_VIDEO_MIXER_ATTRIBUTE_CSC_MATRIX}; + const void *attribute_values[] = {&matrix}; + vdp_st = vdp->video_mixer_set_attribute_values(vc->video_mixer, 1, + attributes, + attribute_values); + CHECK_ST_WARNING("Error when setting CSC matrix"); +} + static int create_vdp_mixer(struct vo *vo, VdpChromaType vdp_chroma_type) { struct vdpctx *vc = vo->priv; @@ -611,6 +640,7 @@ static int create_vdp_mixer(struct vo *vo, VdpChromaType vdp_chroma_type) skip_chroma_attrib, skip_chroma_value_ptr); + update_csc_matrix(vo); return 0; } @@ -803,6 +833,10 @@ static int config(struct vo *vo, uint32_t width, uint32_t height, vc->image_format = format; vc->vid_width = width; vc->vid_height = height; + if (vc->user_colorspace == 0) + vc->colorspace = width >= 1280 || height > 576 ? 1 : 0; + else + vc->colorspace = vc->user_colorspace - 1; free_video_specific(vo); if (IMGFMT_IS_VDPAU(vc->image_format) && !create_vdp_decoder(vo, 2)) return -1; @@ -1543,12 +1577,14 @@ static int preinit(struct vo *vo, const char *arg) vc->deint_type = 3; vc->chroma_deint = 1; + vc->user_colorspace = 1; const opt_t subopts[] = { {"deint", OPT_ARG_INT, &vc->deint, (opt_test_f)int_non_neg}, {"chroma-deint", OPT_ARG_BOOL, &vc->chroma_deint, NULL}, {"pullup", OPT_ARG_BOOL, &vc->pullup, NULL}, {"denoise", OPT_ARG_FLOAT, &vc->denoise, NULL}, {"sharpen", OPT_ARG_FLOAT, &vc->sharpen, NULL}, + {"colorspace", OPT_ARG_INT, &vc->user_colorspace, NULL}, {"fps", OPT_ARG_FLOAT, &vc->user_fps, NULL}, {NULL} }; @@ -1623,11 +1659,6 @@ static int set_equalizer(struct vo *vo, const char *name, int value) { struct vdpctx *vc = vo->priv; struct vdp_functions *vdp = vc->vdp; - VdpStatus vdp_st; - VdpCSCMatrix matrix; - static const VdpVideoMixerAttribute attributes[] = - {VDP_VIDEO_MIXER_ATTRIBUTE_CSC_MATRIX}; - const void *attribute_values[] = {&matrix}; if (!strcasecmp(name, "brightness")) vc->procamp.brightness = value / 100.0; @@ -1640,15 +1671,8 @@ static int set_equalizer(struct vo *vo, const char *name, int value) else return VO_NOTIMPL; - vdp_st = vdp->generate_csc_matrix(&vc->procamp, - VDP_COLOR_STANDARD_ITUR_BT_601, - &matrix); - CHECK_ST_WARNING("Error when generating CSC matrix"); - vdp_st = vdp->video_mixer_set_attribute_values(vc->video_mixer, 1, - attributes, - attribute_values); - CHECK_ST_WARNING("Error when setting CSC matrix"); - return VO_TRUE; + update_csc_matrix(vo); + return true; } static int control(struct vo *vo, uint32_t request, void *data) @@ -1712,6 +1736,13 @@ static int control(struct vo *vo, uint32_t request, void *data) struct voctrl_get_equalizer_args *args = data; return get_equalizer(vo, args->name, args->valueptr); } + case VOCTRL_SET_YUV_COLORSPACE: + vc->colorspace = *(int *)data % 3; + update_csc_matrix(vo); + return true; + case VOCTRL_GET_YUV_COLORSPACE: + *(int *)data = vc->colorspace; + return true; case VOCTRL_ONTOP: vo_x11_ontop(vo); return VO_TRUE; diff --git a/libvo/vo_xv.c b/libvo/vo_xv.c index 886fd0a0d7..9a030ac71c 100644 --- a/libvo/vo_xv.c +++ b/libvo/vo_xv.c @@ -817,6 +817,15 @@ static int control(struct vo *vo, uint32_t request, void *data) struct voctrl_get_equalizer_args *args = data; return vo_xv_get_eq(vo, x11->xv_port, args->name, args->valueptr); } + case VOCTRL_SET_YUV_COLORSPACE:; + int given_cspc = *(int *)data % 2; + return vo_xv_set_eq(vo, x11->xv_port, "bt_709", given_cspc * 200 - 100); + case VOCTRL_GET_YUV_COLORSPACE:; + int bt709_enabled; + if (!vo_xv_get_eq(vo, x11->xv_port, "bt_709", &bt709_enabled)) + return false; + *(int *)data = bt709_enabled == 100; + return true; case VOCTRL_ONTOP: vo_x11_ontop(vo); return VO_TRUE; diff --git a/libvo/x11_common.c b/libvo/x11_common.c index 621880e137..e617aad082 100644 --- a/libvo/x11_common.c +++ b/libvo/x11_common.c @@ -1651,7 +1651,7 @@ double vo_vm_get_fps(struct vo *vo) if (!XF86VidModeGetModeLine(x11->display, x11->screen, &clock, &modeline)) return 0; if (modeline.privsize) - Xfree(modeline.private); + XFree(modeline.private); return 1e3 * clock / modeline.htotal / modeline.vtotal; } #endif @@ -1906,6 +1906,9 @@ int vo_xv_set_eq(struct vo *vo, uint32_t xv_port, char *name, int value) else if (!strcmp(attributes[i].name, "XV_BLUE_INTENSITY") && (!strcasecmp(name, "blue_intensity"))) port_value = value; + else if (!strcmp(attributes[i].name, "XV_ITURBT_709") + && (!strcasecmp(name, "bt_709"))) + port_value = value; else continue; @@ -1987,6 +1990,9 @@ int vo_xv_get_eq(struct vo *vo, uint32_t xv_port, char *name, int *value) else if (!strcmp(attributes[i].name, "XV_BLUE_INTENSITY") && (!strcasecmp(name, "blue_intensity"))) *value = val; + else if (!strcmp(attributes[i].name, "XV_ITURBT_709") + && (!strcasecmp(name, "bt_709"))) + *value = val; else continue; -- cgit v1.2.3