summaryrefslogtreecommitdiffstats
path: root/video
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2013-07-16 23:22:55 +0200
committerwm4 <wm4@nowhere>2013-07-16 23:22:55 +0200
commit18b6c01d921c1dea0986bba4bcd867da5605a3d8 (patch)
tree3489728f82c0270a72005f64590781118b02540f /video
parenta98aad61f854d9a216675dc54096aa39767c4a35 (diff)
downloadmpv-18b6c01d921c1dea0986bba4bcd867da5605a3d8.tar.bz2
mpv-18b6c01d921c1dea0986bba4bcd867da5605a3d8.tar.xz
video: redo how colorspaces are handled
Instead of handling colorspaces with VFCTRLs/VOCTRLs, make them part of the normal video format negotiation. The colorspace is passed down like other video params with config/reconfig calls. Forcing colorspaces (via the --colormatrix options and properties) is handled differently too: if it's changed, completely reinit the video chain. This is slower and requires a precise seek to the same position to perform an update, but it's simpler and less bug-prone. Considering switching the colorspace at runtime by user-interaction is a rather obscure feature, this is a good change. The colorspace VFCTRLs and VOCTRLs are still kept. The VOs rely on it, and would have to be changed to get rid of them. We'll do that later, and convert them incrementally instead of in one go. Note that controlling the output range now always works on VO level. Basically, this means you can't get vf_scale to output full-range YUV for whatever reason. If that is really wanted, it should be a vf_scale option. the previous behavior didn't make too much sense anyway. This commit fixes a few bugs (such as playing RGB video and converting that to YUV with vf_scale - a recent commit broke this and forced the VO to display YUV as RGB if possible), and might introduce some new ones.
Diffstat (limited to 'video')
-rw-r--r--video/decode/dec_video.c51
-rw-r--r--video/decode/dec_video.h2
-rw-r--r--video/decode/vd.c10
-rw-r--r--video/filter/vf.c17
-rw-r--r--video/filter/vf_scale.c69
-rw-r--r--video/filter/vf_sub.c12
-rw-r--r--video/mp_image.c2
-rw-r--r--video/out/vo.c9
8 files changed, 70 insertions, 102 deletions
diff --git a/video/decode/dec_video.c b/video/decode/dec_video.c
index cd9e8be1e5..595ffb0e16 100644
--- a/video/decode/dec_video.c
+++ b/video/decode/dec_video.c
@@ -106,62 +106,27 @@ int get_video_colors(sh_video_t *sh_video, const char *item, int *value)
// This is affected by user-specified overrides (aspect, colorspace...).
bool get_video_params(struct sh_video *sh, struct mp_image_params *p)
{
- struct MPOpts *opts = sh->opts;
-
if (!sh->vf_input)
return false;
*p = *sh->vf_input;
-
- // Apply user overrides
- if (opts->requested_colorspace != MP_CSP_AUTO)
- p->colorspace = opts->requested_colorspace;
- if (opts->requested_input_range != MP_CSP_LEVELS_AUTO)
- p->colorlevels = opts->requested_input_range;
-
- // Make sure the user-overrides are consistent (no RGB csp for YUV, etc.)
- mp_image_params_guess_csp(p);
-
return true;
}
-void set_video_colorspace(struct sh_video *sh)
+void set_video_output_levels(struct sh_video *sh)
{
struct MPOpts *opts = sh->opts;
- struct vf_instance *vf = sh->vfilter;
- struct mp_image_params params;
- if (!get_video_params(sh, &params))
+ if (!sh->vfilter)
return;
- struct mp_csp_details requested = {
- .format = params.colorspace,
- .levels_in = params.colorlevels,
- .levels_out = opts->requested_output_range,
- };
- if (requested.levels_out == MP_CSP_LEVELS_AUTO)
- requested.levels_out = MP_CSP_LEVELS_PC;
-
- 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);
+ struct mp_csp_details csp;
+ if (vf_control(sh->vfilter, VFCTRL_GET_YUV_COLORSPACE, &csp) > 0) {
+ csp.levels_out = opts->requested_output_range;
+ if (csp.levels_out == MP_CSP_LEVELS_AUTO)
+ csp.levels_out = MP_CSP_LEVELS_PC;
+ vf_control(sh->vfilter, VFCTRL_SET_YUV_COLORSPACE, &csp);
}
-
}
void resync_video_stream(sh_video_t *sh_video)
diff --git a/video/decode/dec_video.h b/video/decode/dec_video.h
index 88161ee54f..141442fa19 100644
--- a/video/decode/dec_video.h
+++ b/video/decode/dec_video.h
@@ -39,7 +39,7 @@ 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_image_params;
bool get_video_params(struct sh_video *sh, struct mp_image_params *p);
-void set_video_colorspace(struct sh_video *sh);
+void set_video_output_levels(struct sh_video *sh);
void resync_video_stream(sh_video_t *sh_video);
void video_reinit_vo(struct sh_video *sh_video);
int get_current_video_decoder_lag(sh_video_t *sh_video);
diff --git a/video/decode/vd.c b/video/decode/vd.c
index b344491c6b..98b9b155df 100644
--- a/video/decode/vd.c
+++ b/video/decode/vd.c
@@ -152,6 +152,14 @@ int mpcodecs_reconfig_vo(sh_video_t *sh, const struct mp_image_params *params)
p.d_w = d_w;
p.d_h = d_h;
+ // Apply user overrides
+ if (opts->requested_colorspace != MP_CSP_AUTO)
+ p.colorspace = opts->requested_colorspace;
+ if (opts->requested_input_range != MP_CSP_LEVELS_AUTO)
+ p.colorlevels = opts->requested_input_range;
+
+ // Detect colorspace from resolution.
+ // Make sure the user-overrides are consistent (no RGB csp for YUV, etc.).
mp_image_params_guess_csp(&p);
vocfg_flags = (opts->fullscreen ? VOFLAG_FULLSCREEN : 0) |
@@ -177,7 +185,7 @@ int mpcodecs_reconfig_vo(sh_video_t *sh, const struct mp_image_params *params)
sh->vf_input = talloc(sh, struct mp_image_params);
*sh->vf_input = p;
- set_video_colorspace(sh);
+ set_video_output_levels(sh);
if (opts->gamma_gamma != 1000)
set_video_colors(sh, "gamma", opts->gamma_gamma);
diff --git a/video/filter/vf.c b/video/filter/vf.c
index 1570e8402c..8946aeb801 100644
--- a/video/filter/vf.c
+++ b/video/filter/vf.c
@@ -170,6 +170,8 @@ static void print_fmt(int msglevel, struct vf_format *fmt)
mp_msg(MSGT_VFILTER, msglevel, "->%dx%d", p->d_w, p->d_h);
mp_msg(MSGT_VFILTER, msglevel, " %s %#x", mp_imgfmt_to_name(p->imgfmt),
fmt->flags);
+ mp_msg(MSGT_VFILTER, msglevel, " %s/%s", mp_csp_names[p->colorspace],
+ mp_csp_levels_names[p->colorlevels]);
} else {
mp_msg(MSGT_VFILTER, msglevel, "???");
}
@@ -357,8 +359,19 @@ unsigned int vf_match_csp(vf_instance_t **vfp, const unsigned int *list,
// Ownership of img is transferred from caller to the filter chain.
void vf_add_output_frame(struct vf_instance *vf, struct mp_image *img)
{
- if (img)
+ if (img) {
+ struct mp_image_params *p = &vf->fmt_out.params;
+ // vf_vo doesn't have output config
+ if (vf->fmt_out.configured) {
+ assert(p->imgfmt == img->imgfmt);
+ assert(p->w == img->w && p->h == img->h);
+ // Too many filters which don't set these correctly
+ img->colorspace = p->colorspace;
+ img->levels = p->colorlevels;
+ img->chroma_location = p->chroma_location;
+ }
MP_TARRAY_APPEND(vf, vf->out_queued, vf->num_out_queued, img);
+ }
}
static struct mp_image *vf_dequeue_output_frame(struct vf_instance *vf)
@@ -486,6 +499,8 @@ int vf_next_config(struct vf_instance *vf,
.colorlevels = vf->fmt_in.params.colorlevels,
.chroma_location = vf->fmt_in.params.chroma_location,
};
+ // Fix csp in case of pixel format change
+ mp_image_params_guess_csp(&p);
int r = vf_reconfig_wrapper(vf->next, &p, voflags);
return r < 0 ? 0 : 1;
}
diff --git a/video/filter/vf_scale.c b/video/filter/vf_scale.c
index f357581bb3..2a1c397807 100644
--- a/video/filter/vf_scale.c
+++ b/video/filter/vf_scale.c
@@ -50,7 +50,6 @@ static struct vf_priv_s {
int interlaced;
int noup;
int accurate_rnd;
- struct mp_csp_details colorspace;
} const vf_priv_dflt = {
0, 0,
-1,-1,
@@ -59,7 +58,7 @@ static struct vf_priv_s {
};
static int mp_sws_set_colorspace(struct SwsContext *sws,
- struct mp_csp_details *csp);
+ struct mp_image_params *p);
//===========================================================================//
@@ -197,20 +196,19 @@ static unsigned int find_best_out(vf_instance_t *vf, int in_format){
return best;
}
-static int config(struct vf_instance *vf,
- int width, int height, int d_width, int d_height,
- unsigned int flags, unsigned int outfmt){
+static int reconfig(struct vf_instance *vf, struct mp_image_params *p, int flags)
+{
+ int width = p->w, height = p->h, d_width = p->d_w, d_height = p->d_h;
+ unsigned int outfmt = p->imgfmt;
unsigned int best=find_best_out(vf, outfmt);
int int_sws_flags=0;
int round_w=0, round_h=0;
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;
+ return -1;
}
sfmt = imgfmt2pixfmt(outfmt);
dfmt = imgfmt2pixfmt(best);
@@ -235,7 +233,7 @@ static int config(struct vf_instance *vf,
// and find out what the heck he thinks MPlayer should do
// with this nonsense.
mp_msg(MSGT_VFILTER, MSGL_ERR, "SwScale: EUSERBROKEN Check your parameters, they make no sense!\n");
- return 0;
+ return -1;
}
if (vf->priv->w == -1)
@@ -301,7 +299,7 @@ static int config(struct vf_instance *vf,
if(!vf->priv->ctx){
// error...
mp_msg(MSGT_VFILTER,MSGL_WARN,"Couldn't init SwScaler for this setup\n");
- return 0;
+ return -1;
}
vf->priv->fmt=best;
// Compute new d_width and d_height, preserving aspect
@@ -315,7 +313,17 @@ static int config(struct vf_instance *vf,
}
//d_width=d_width*vf->priv->w/width;
//d_height=d_height*vf->priv->h/height;
- return vf_next_config(vf,vf->priv->w,vf->priv->h,d_width,d_height,flags,best);
+ p->w = vf->priv->w;
+ p->h = vf->priv->h;
+ p->d_w = d_width;
+ p->d_h = d_height;
+ p->imgfmt = best;
+ mp_sws_set_colorspace(vf->priv->ctx, p);
+ // In particular, fix up colorspace/levels if YUV<->RGB conversion is
+ // performed.
+ p->colorlevels = MP_CSP_LEVELS_TV; // in case output is YUV
+ mp_image_params_guess_csp(p);
+ return vf_next_reconfig(vf, p, flags);
}
static void scale(struct SwsContext *sws1, struct SwsContext *sws2, uint8_t *src[MP_MAX_PLANES], int src_stride[MP_MAX_PLANES],
@@ -407,30 +415,6 @@ static int control(struct vf_instance *vf, int request, void* data){
if(r<0) break;
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) {
- 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;
}
@@ -446,26 +430,22 @@ static const int mp_csp_to_swscale[MP_CSP_COUNT] = {
// 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.
static int mp_sws_set_colorspace(struct SwsContext *sws,
- struct mp_csp_details *csp)
+ struct mp_image_params *p)
{
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];
+ int sws_csp = mp_csp_to_swscale[p->colorspace];
if (sws_csp == 0) {
// colorspace not supported, go with a reasonable default
- csp->format = SWS_CS_ITU601;
- sws_csp = MP_CSP_BT_601;
+ sws_csp = SWS_CS_ITU601;
}
/* The swscale API for these is hardly documented.
@@ -473,7 +453,7 @@ static int mp_sws_set_colorspace(struct SwsContext *sws,
* for YUV->RGB conversions, and conversions to limited-range RGB are
* not supported.
*/
- srcRange = csp->levels_in == MP_CSP_LEVELS_PC;
+ srcRange = p->colorlevels == MP_CSP_LEVELS_PC;
const int *new_inv_table = sws_getCoefficients(sws_csp);
if (sws_setColorspaceDetails(sws, new_inv_table, srcRange, table, dstRange,
@@ -483,7 +463,6 @@ static int mp_sws_set_colorspace(struct SwsContext *sws,
return 0;
error_out:
- *csp = (struct mp_csp_details){0};
return -1;
}
@@ -509,7 +488,7 @@ static void uninit(struct vf_instance *vf){
}
static int vf_open(vf_instance_t *vf, char *args){
- vf->config=config;
+ vf->reconfig=reconfig;
vf->filter=filter;
vf->query_format=query_format;
vf->control= control;
diff --git a/video/filter/vf_sub.c b/video/filter/vf_sub.c
index e918574c30..e85a58afb7 100644
--- a/video/filter/vf_sub.c
+++ b/video/filter/vf_sub.c
@@ -39,7 +39,6 @@
#include "video/sws_utils.h"
#include "video/memcpy_pic.h"
-#include "video/csputils.h"
#include "core/m_option.h"
#include "core/m_struct.h"
@@ -49,12 +48,10 @@ static const struct vf_priv_s {
int outh, outw;
- struct mp_csp_details csp;
-
struct osd_state *osd;
struct mp_osd_res dim;
} vf_priv_dflt = {
- .csp = MP_CSP_DETAILS_DEFAULTS,
+ 0
};
static int config(struct vf_instance *vf,
@@ -109,8 +106,6 @@ static struct mp_image *filter(struct vf_instance *vf, struct mp_image *mpi)
mpi = dmpi;
}
- mp_image_set_colorspace_details(mpi, &priv->csp);
-
osd_draw_on_image_p(osd, priv->dim, mpi->pts, OSD_DRAW_SUB_FILTER,
vf->out_pool, mpi);
@@ -132,11 +127,6 @@ static int control(vf_instance_t *vf, int request, void *data)
break;
case VFCTRL_INIT_OSD:
return CONTROL_TRUE;
- case VFCTRL_SET_YUV_COLORSPACE: {
- struct mp_csp_details colorspace = *(struct mp_csp_details *)data;
- vf->priv->csp = colorspace;
- break;
- }
}
return vf_next_control(vf, request, data);
}
diff --git a/video/mp_image.c b/video/mp_image.c
index c1e4ba18e7..029c5fa91b 100644
--- a/video/mp_image.c
+++ b/video/mp_image.c
@@ -439,6 +439,8 @@ void mp_image_set_colorspace_details(struct mp_image *image,
{
struct mp_image_params params;
mp_image_params_from_image(&params, image);
+ params.colorspace = csp->format;
+ params.colorlevels = csp->levels_in;
mp_image_params_guess_csp(&params);
image->colorspace = params.colorspace;
image->levels = params.colorlevels;
diff --git a/video/out/vo.c b/video/out/vo.c
index e05b1ae8a6..425c49aab8 100644
--- a/video/out/vo.c
+++ b/video/out/vo.c
@@ -441,6 +441,15 @@ int vo_reconfig(struct vo *vo, struct mp_image_params *params, int flags)
vo->waiting_mpi = NULL;
vo->redrawing = false;
vo->hasframe = false;
+ if (vo->config_ok) {
+ // Legacy
+ struct mp_csp_details csp;
+ if (vo_control(vo, VOCTRL_GET_YUV_COLORSPACE, &csp) > 0) {
+ csp.levels_in = params->colorlevels;
+ csp.format = params->colorspace;
+ vo_control(vo, VOCTRL_SET_YUV_COLORSPACE, &csp);
+ }
+ }
return ret;
}