diff options
Diffstat (limited to 'libmpcodecs')
-rw-r--r-- | libmpcodecs/dec_video.c | 46 | ||||
-rw-r--r-- | libmpcodecs/dec_video.h | 3 | ||||
-rw-r--r-- | libmpcodecs/vd.c | 3 | ||||
-rw-r--r-- | libmpcodecs/vf.h | 4 | ||||
-rw-r--r-- | libmpcodecs/vf_scale.c | 79 | ||||
-rw-r--r-- | libmpcodecs/vf_scale.h | 3 |
6 files changed, 136 insertions, 2 deletions
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 */ |