diff options
-rw-r--r-- | DOCS/man/options.rst | 16 | ||||
-rw-r--r-- | TOOLS/lib/Parse/Matroska/Definitions.pm | 1 | ||||
-rw-r--r-- | demux/demux_mkv.c | 12 | ||||
-rw-r--r-- | demux/stheader.h | 1 | ||||
-rw-r--r-- | options/m_option.c | 53 | ||||
-rw-r--r-- | options/m_option.h | 6 | ||||
-rw-r--r-- | options/options.c | 1 | ||||
-rw-r--r-- | options/options.h | 1 | ||||
-rw-r--r-- | player/video.c | 12 | ||||
-rw-r--r-- | video/csputils.c | 22 | ||||
-rw-r--r-- | video/csputils.h | 11 | ||||
-rw-r--r-- | video/decode/vd_lavc.c | 2 | ||||
-rw-r--r-- | video/filter/vf_stereo3d.c | 2 | ||||
-rw-r--r-- | video/mp_image.c | 6 | ||||
-rw-r--r-- | video/mp_image.h | 2 |
15 files changed, 146 insertions, 2 deletions
diff --git a/DOCS/man/options.rst b/DOCS/man/options.rst index 0062165f0c..87f7eb54b2 100644 --- a/DOCS/man/options.rst +++ b/DOCS/man/options.rst @@ -561,6 +561,22 @@ Video which means the value ``0`` would rotate the video according to the rotation metadata.) +``--video-stereo-mode=<mode>`` + Set the stereo 3D output mode (default: ``mono``). This is done by inserting + the ``stereo3d`` conversion filter. + + The mode ``mono`` is an alias to ``ml``, which refers to the left frame in + 2D. This is the default, which means mpv will try to show 3D movies in 2D, + instead of the mangled 3D image not intended for consumption (such as + showing the left and right frame side by side, etc.). + + The pseudo-mode ``none`` disables automatic conversion completely. + + Use ``--video-stereo-mode=help`` to list all available modes. Check with + the ``stereo3d`` filter documentation to see what the names mean. Note that + some names refer to modes not supported by ``stereo3d`` - these modes can + appear in files, but can't be handled properly by mpv. + ``--video-zoom=<value>`` Adjust the video display scale factor by the given value. The unit is in fractions of the (scaled) window video size. diff --git a/TOOLS/lib/Parse/Matroska/Definitions.pm b/TOOLS/lib/Parse/Matroska/Definitions.pm index c52c2172b3..081fe5bb97 100644 --- a/TOOLS/lib/Parse/Matroska/Definitions.pm +++ b/TOOLS/lib/Parse/Matroska/Definitions.pm @@ -265,6 +265,7 @@ sub define_matroska { elem('DisplayUnit', '54b2', 'uint'), elem('FrameRate', '2383e3', 'float'), elem('ColourSpace', '2eb524', 'binary'), + elem('StereoMode', '53b8', 'uint'), }), elem('Audio', 'e1', { elem('SamplingFrequency', 'b5', 'float'), diff --git a/demux/demux_mkv.c b/demux/demux_mkv.c index 02efcb2a0a..1f4ef89e34 100644 --- a/demux/demux_mkv.c +++ b/demux/demux_mkv.c @@ -46,6 +46,7 @@ #include "options/options.h" #include "misc/bstr.h" #include "stream/stream.h" +#include "video/csputils.h" #include "demux.h" #include "stheader.h" #include "ebml.h" @@ -102,6 +103,7 @@ typedef struct mkv_track { bool v_dwidth_set, v_dheight_set; double v_frate; uint32_t colorspace; + int stereo_mode; uint32_t a_formattag; uint32_t a_channels, a_bps; @@ -504,6 +506,15 @@ static void parse_trackvideo(struct demuxer *demuxer, struct mkv_track *track, MP_VERBOSE(demuxer, "| + Colorspace: %#x\n", (unsigned int)track->colorspace); } + if (video->n_stereo_mode) { + const char *name = MP_STEREO3D_NAME(video->stereo_mode); + if (name) { + track->stereo_mode = video->stereo_mode; + MP_VERBOSE(demuxer, "| + StereoMode: %s\n", name); + } else { + MP_WARN(demuxer, "Unknown StereoMode: %d\n", (int)video->stereo_mode); + } + } } /** @@ -1276,6 +1287,7 @@ static int demux_mkv_open_video(demuxer_t *demuxer, mkv_track_t *track) } MP_VERBOSE(demuxer, "Aspect: %f\n", sh_v->aspect); sh_v->avi_dts = track->ms_compat; + sh_v->stereo_mode = track->stereo_mode; return 0; } diff --git a/demux/stheader.h b/demux/stheader.h index 082fffa5e2..3fc8c999d4 100644 --- a/demux/stheader.h +++ b/demux/stheader.h @@ -82,6 +82,7 @@ typedef struct sh_video { int bitrate; // compressed bits/sec int disp_w, disp_h; // display size int rotate; // intended display rotation, in degrees, [0, 359] + int stereo_mode; // mp_stereo3d_mode (0 if none/unknown) MP_BITMAPINFOHEADER *bih; } sh_video_t; diff --git a/options/m_option.c b/options/m_option.c index 6ab1fc1f7a..a84d7e4d41 100644 --- a/options/m_option.c +++ b/options/m_option.c @@ -1983,6 +1983,59 @@ const m_option_type_t m_option_type_imgfmt = { .copy = copy_opt, }; +#include "video/csputils.h" + +static int parse_stereo_mode(struct mp_log *log, const m_option_t *opt, + struct bstr name, struct bstr param, void *dst) +{ + if (param.len == 0) + return M_OPT_MISSING_PARAM; + + if (!bstrcmp0(param, "help")) { + mp_info(log, "Available modes:"); + for (int n = 0; n < MP_STEREO3D_COUNT; n++) { + if (mp_stereo3d_names[n]) + mp_info(log, " %s\n", mp_stereo3d_names[n]); + } + mp_info(log, " none\n"); + return M_OPT_EXIT - 1; + } + + int mode = -1; + + for (int n = 0; n < MP_STEREO3D_COUNT; n++) { + if (bstr_equals(param, bstr0(mp_stereo3d_names[n]))) { + mode = n; + break; + } + } + + if (mode < 0 && !bstr_equals0(param, "none")) { + mp_err(log, "Option %.*s: unknown parameter: '%.*s'\n", + BSTR_P(name), BSTR_P(param)); + return M_OPT_INVALID; + } + + if (dst) + *((int *)dst) = mode; + + return 1; +} + +static char *print_stereo_mode(const m_option_t *opt, const void *val) +{ + int mode = *(int *)val; + const char *name = mode >= 0 ? MP_STEREO3D_NAME(mode) : "none"; + return talloc_strdup(NULL, name); +} + +const m_option_type_t m_option_vid_stereo_mode = { + .name = "Stereo 3D mode", + .size = sizeof(int), + .parse = parse_stereo_mode, + .print = print_stereo_mode, +}; + static int parse_fourcc(struct mp_log *log, const m_option_t *opt, struct bstr name, struct bstr param, void *dst) { diff --git a/options/m_option.h b/options/m_option.h index d0ca211aa1..d7541a5c73 100644 --- a/options/m_option.h +++ b/options/m_option.h @@ -56,6 +56,7 @@ extern const m_option_type_t m_option_type_msglevels; extern const m_option_type_t m_option_type_print_fn; extern const m_option_type_t m_option_type_subconfig; extern const m_option_type_t m_option_type_imgfmt; +extern const m_option_type_t m_option_vid_stereo_mode; extern const m_option_type_t m_option_type_fourcc; extern const m_option_type_t m_option_type_afmt; extern const m_option_type_t m_option_type_color; @@ -648,8 +649,11 @@ extern const char m_option_path_separator; #define OPT_TRACKCHOICE(name, var) \ OPT_CHOICE_OR_INT(name, var, 0, 1, 8190, ({"no", -2}, {"auto", -1})) +#define OPT_VID_STEREO_MODE(...) \ + OPT_GENERAL(int, __VA_ARGS__, .type = &m_option_vid_stereo_mode) + #define OPT_STRING_VALIDATE_(optname, varname, flags, validate_fn, ...) \ - OPT_GENERAL(char*, optname, varname, flags, __VA_ARGS__, \ + OPT_GENERAL(char*, optname, varname, flags, __VA_ARGS__, \ .priv = MP_EXPECT_TYPE(m_opt_string_validate_fn, validate_fn)) #define OPT_STRING_VALIDATE(...) \ OPT_STRING_VALIDATE_(__VA_ARGS__, .type = &m_option_type_string) diff --git a/options/options.c b/options/options.c index 0f97528ba1..00c8c0fbb5 100644 --- a/options/options.c +++ b/options/options.c @@ -415,6 +415,7 @@ const m_option_t mp_opts[] = { {"BT.2020", MP_CSP_PRIM_BT_2020})), OPT_CHOICE_OR_INT("video-rotate", video_rotate, 0, 0, 359, ({"no", -1})), + OPT_VID_STEREO_MODE("video-stereo-mode", video_stereo_mode, 0), OPT_CHOICE_OR_INT("cursor-autohide", cursor_autohide_delay, 0, 0, 30000, ({"no", -1}, {"always", -2})), diff --git a/options/options.h b/options/options.h index 4468d2abbd..701c9e236b 100644 --- a/options/options.h +++ b/options/options.h @@ -98,6 +98,7 @@ typedef struct MPOpts { int requested_primaries; int video_rotate; + int video_stereo_mode; char *audio_decoders; char *video_decoders; diff --git a/player/video.c b/player/video.c index 7aaef07f4f..f36a41b8f7 100644 --- a/player/video.c +++ b/player/video.c @@ -157,6 +157,18 @@ static void filter_reconfig(struct MPContext *mpctx, } } } + + if (params.stereo_in != params.stereo_out && + params.stereo_in > 0 && params.stereo_out >= 0) + { + char *from = MP_STEREO3D_NAME(params.stereo_in); + char *to = MP_STEREO3D_NAME(params.stereo_out); + if (from && to) { + char *args[] = {"in", from, "out", to, NULL, NULL}; + if (try_filter(mpctx, params, "stereo3d", "stereo3d", args) < 0) + MP_ERR(mpctx, "Can't insert 3D conversion filter.\n"); + } + } } static void recreate_video_filters(struct MPContext *mpctx) diff --git a/video/csputils.c b/video/csputils.c index 1cbaf47de9..d07b3a096e 100644 --- a/video/csputils.c +++ b/video/csputils.c @@ -77,6 +77,28 @@ const char *const mp_chroma_names[MP_CHROMA_COUNT] = { "mpeg1/jpeg", }; +// The short name _must_ match with what vf_stereo3d accepts (if supported). +// The long name is closer to the Matroska spec (StereoMode element). +// If you add entries that don't match Matroska, make sure demux_mkv.c rejects +// them properly. +// The long name is unused. +#define E(index, short, long) [index] = short +const char *const mp_stereo3d_names[MP_STEREO3D_COUNT] = { + E(0, "mono", "mono"), // unsupported by vf_stereo3d + E(1, "sbs2l", "side_by_side_left"), + E(2, "abr", "top_bottom_right"), + E(3, "abl", "top_bottom_left"), + E(4, "checkr", "checkboard_right"), // unsupported by vf_stereo3d + E(5, "checkl", "checkboard_left"), + E(6, "irr", "row_interleaved_right"), + E(7, "irl", "row_interleaved_left"), + E(8, "icr", "column_interleaved_right"),// unsupported by vf_stereo3d + E(9, "icl", "column_interleaved_left"), // unsupported by vf_stereo3d + E(10, "arcc", "anaglyph_cyan_red"), // Matroska: unclear which mode + E(11, "sbs2r", "side_by_side_right"), + E(12, "agmc", "anaglyph_green_magenta"), // Matroska: unclear which mode +}; + enum mp_csp avcol_spc_to_mp_csp(int avcolorspace) { switch (avcolorspace) { diff --git a/video/csputils.h b/video/csputils.h index 757ac72cdc..1a559ebfd2 100644 --- a/video/csputils.h +++ b/video/csputils.h @@ -79,6 +79,17 @@ enum mp_render_intent { MP_INTENT_ABSOLUTE_COLORIMETRIC = 3 }; +enum mp_stereo3d_mode { + MP_STEREO3D_INVALID = -1, + MP_STEREO3D_MONO = 0, + MP_STEREO3D_COUNT = 13, // 12 is last valid mode +}; + +extern const char *const mp_stereo3d_names[MP_STEREO3D_COUNT]; + +#define MP_STEREO3D_NAME(x) \ + ((x) >= 0 && (x) < MP_STEREO3D_COUNT ? (char *)mp_stereo3d_names[(x)] : NULL) + struct mp_csp_details { enum mp_csp format; enum mp_csp_levels levels_in; // encoded video diff --git a/video/decode/vd_lavc.c b/video/decode/vd_lavc.c index 1d33742bc5..45ae9fce94 100644 --- a/video/decode/vd_lavc.c +++ b/video/decode/vd_lavc.c @@ -485,6 +485,7 @@ static void update_image_params(struct dec_video *vd, AVFrame *frame, .chroma_location = avchroma_location_to_mp(ctx->avctx->chroma_sample_location), .rotate = vd->header->video->rotate, + .stereo_in = vd->header->video->stereo_mode, }; if (opts->video_rotate < 0) { @@ -492,6 +493,7 @@ static void update_image_params(struct dec_video *vd, AVFrame *frame, } else { out_params->rotate = (out_params->rotate + opts->video_rotate) % 360; } + out_params->stereo_out = opts->video_stereo_mode; } static enum AVPixelFormat get_format_hwdec(struct AVCodecContext *avctx, diff --git a/video/filter/vf_stereo3d.c b/video/filter/vf_stereo3d.c index 15d2095f5d..fcf583eef4 100644 --- a/video/filter/vf_stereo3d.c +++ b/video/filter/vf_stereo3d.c @@ -445,6 +445,8 @@ const struct m_opt_choice_alternatives stereo_code_names[] = { {"interleave_rows_left_first", INTERLEAVE_ROWS_LR}, {"irr", INTERLEAVE_ROWS_RL}, {"interleave_rows_right_first", INTERLEAVE_ROWS_RL}, + // convenience alias for MP_STEREO3D_MONO + {"mono", MONO_L}, { NULL, 0} }; diff --git a/video/mp_image.c b/video/mp_image.c index d83a9ae3c1..7b430dfaf6 100644 --- a/video/mp_image.c +++ b/video/mp_image.c @@ -364,6 +364,8 @@ void mp_image_copy_attributes(struct mp_image *dst, struct mp_image *src) dst->fields = src->fields; dst->qscale_type = src->qscale_type; dst->pts = src->pts; + dst->params.stereo_in = src->params.stereo_in; + dst->params.stereo_out = src->params.stereo_out; if (dst->w == src->w && dst->h == src->h) { dst->params.d_w = src->params.d_w; dst->params.d_h = src->params.d_h; @@ -489,7 +491,9 @@ bool mp_image_params_equal(const struct mp_image_params *p1, p1->outputlevels == p2->outputlevels && p1->primaries == p2->primaries && p1->chroma_location == p2->chroma_location && - p1->rotate == p2->rotate; + p1->rotate == p2->rotate && + p1->stereo_in == p2->stereo_in && + p1->stereo_out == p2->stereo_out; } // Set most image parameters, but not image format or size. diff --git a/video/mp_image.h b/video/mp_image.h index 5ab12ae3d8..9cdc7fdf77 100644 --- a/video/mp_image.h +++ b/video/mp_image.h @@ -55,6 +55,8 @@ struct mp_image_params { enum mp_csp_levels outputlevels; // The image should be rotated clockwise (0-359 degrees). int rotate; + enum mp_stereo3d_mode stereo_in; // image is encoded with this mode + enum mp_stereo3d_mode stereo_out; // should be displayed with this mode }; /* Memory management: |