summaryrefslogtreecommitdiffstats
path: root/libmpcodecs
diff options
context:
space:
mode:
Diffstat (limited to 'libmpcodecs')
-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
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 */