diff options
-rw-r--r-- | DOCS/man/vf.rst | 10 | ||||
-rwxr-xr-x | TOOLS/matroska.py | 7 | ||||
-rw-r--r-- | demux/demux_lavf.c | 17 | ||||
-rw-r--r-- | demux/demux_mkv.c | 47 | ||||
-rw-r--r-- | demux/stheader.h | 3 | ||||
-rw-r--r-- | video/decode/dec_video.c | 4 | ||||
-rw-r--r-- | video/filter/vf.c | 2 | ||||
-rw-r--r-- | video/filter/vf_format.c | 15 | ||||
-rw-r--r-- | video/mp_image.c | 28 | ||||
-rw-r--r-- | video/mp_image.h | 17 | ||||
-rw-r--r-- | wscript | 6 |
11 files changed, 152 insertions, 4 deletions
diff --git a/DOCS/man/vf.rst b/DOCS/man/vf.rst index 9ed8f2f047..0c43698149 100644 --- a/DOCS/man/vf.rst +++ b/DOCS/man/vf.rst @@ -414,6 +414,16 @@ Available mpv-only filters are: but values such as ``[16:9]`` can be passed too (``[...]`` for quoting to prevent the option parser from interpreting the ``:`` character). + ``<spherical-type>`` + Type of the spherical projection: + + :auto: As indicated by the file (default) + :none: Normal video + :equirect: Equirectangular + :unknown: Unknown projection + + ``<spherical-yaw>``, ``<spherical-pitch>``, ``<spherical-roll>`` + Reference angle in degree, if spherical video is used. ``noformat[=fmt]`` Restricts the color space for the next filter without doing any conversion. diff --git a/TOOLS/matroska.py b/TOOLS/matroska.py index 2b59d2d8c0..bf9a0f2eef 100755 --- a/TOOLS/matroska.py +++ b/TOOLS/matroska.py @@ -137,6 +137,13 @@ elements_matroska = ( 'LuminanceMin, 55DA, float', ), ), + 'Projection, 7670, sub', ( + 'ProjectionType, 7671, uint', + 'ProjectionPrivate, 7672, binary', + 'ProjectionPoseYaw, 7673, float', + 'ProjectionPosePitch, 7674, float', + 'ProjectionPoseRoll, 7675, float', + ), ), 'Audio, e1, sub', ( 'SamplingFrequency, b5, float', diff --git a/demux/demux_lavf.c b/demux/demux_lavf.c index f890b5d693..e61529fb71 100644 --- a/demux/demux_lavf.c +++ b/demux/demux_lavf.c @@ -38,6 +38,10 @@ #include <libavutil/display.h> #include <libavutil/opt.h> +#if HAVE_AVUTIL_SPHERICAL +#include <libavutil/spherical.h> +#endif + #include "common/msg.h" #include "common/tags.h" #include "common/av_common.h" @@ -641,6 +645,19 @@ static void handle_new_stream(demuxer_t *demuxer, int i) sh->codec->rotate = (((int)(-r) % 360) + 360) % 360; } +#if HAVE_AVUTIL_SPHERICAL + sd = av_stream_get_side_data(st, AV_PKT_DATA_SPHERICAL, NULL); + if (sd) { + AVSphericalMapping *sp = (void *)sd; + struct mp_spherical_params *mpsp = &sh->codec->spherical; + mpsp->type = sp->projection == AV_SPHERICAL_EQUIRECTANGULAR ? + MP_SPHERICAL_EQUIRECTANGULAR : MP_SPHERICAL_UNKNOWN; + mpsp->ref_angles[0] = sp->yaw / (float)(1 << 16); + mpsp->ref_angles[1] = sp->pitch / (float)(1 << 16); + mpsp->ref_angles[2] = sp->roll / (float)(1 << 16); + } +#endif + // This also applies to vfw-muxed mkv, but we can't detect these easily. sh->codec->avi_dts = matches_avinputformat_name(priv, "avi"); diff --git a/demux/demux_mkv.c b/demux/demux_mkv.c index 9f670e2aa5..4b9551adae 100644 --- a/demux/demux_mkv.c +++ b/demux/demux_mkv.c @@ -109,6 +109,7 @@ typedef struct mkv_track { uint32_t colorspace; int stereo_mode; struct mp_colorspace color; + struct mp_spherical_params spherical; uint32_t a_channels, a_bps; float a_sfreq; @@ -584,6 +585,49 @@ static void parse_trackcolour(struct demuxer *demuxer, struct mkv_track *track, } } +static void parse_trackprojection(struct demuxer *demuxer, struct mkv_track *track, + struct ebml_projection *projection) +{ + if (projection->n_projection_type) { + const char *name; + switch (projection->projection_type) { + case 0: + name = "rectangular"; + track->spherical.type = MP_SPHERICAL_NONE; + break; + case 1: + name = "equirectangular"; + track->spherical.type = MP_SPHERICAL_EQUIRECTANGULAR; + break; + default: + name = "unknown"; + track->spherical.type = MP_SPHERICAL_UNKNOWN; + } + MP_VERBOSE(demuxer, "| + ProjectionType: %s (%"PRIu64")\n", name, + projection->projection_type); + } + if (projection->n_projection_private) { + MP_VERBOSE(demuxer, "| + ProjectionPrivate: %zd bytes\n", + projection->projection_private.len); + MP_WARN(demuxer, "Unknown ProjectionPrivate element.\n"); + } + if (projection->n_projection_pose_yaw) { + track->spherical.ref_angles[0] = projection->projection_pose_yaw; + MP_VERBOSE(demuxer, "| + ProjectionPoseYaw: %f\n", + projection->projection_pose_yaw); + } + if (projection->n_projection_pose_pitch) { + track->spherical.ref_angles[1] = projection->projection_pose_pitch; + MP_VERBOSE(demuxer, "| + ProjectionPosePitch: %f\n", + projection->projection_pose_pitch); + } + if (projection->n_projection_pose_roll) { + track->spherical.ref_angles[2] = projection->projection_pose_roll; + MP_VERBOSE(demuxer, "| + ProjectionPoseRoll: %f\n", + projection->projection_pose_roll); + } +} + static void parse_trackvideo(struct demuxer *demuxer, struct mkv_track *track, struct ebml_video *video) { @@ -628,6 +672,8 @@ static void parse_trackvideo(struct demuxer *demuxer, struct mkv_track *track, } if (video->n_colour) parse_trackcolour(demuxer, track, &video->colour); + if (video->n_projection) + parse_trackprojection(demuxer, track, &video->projection); } /** @@ -1454,6 +1500,7 @@ static int demux_mkv_open_video(demuxer_t *demuxer, mkv_track_t *track) sh_v->stereo_mode = track->stereo_mode; sh_v->color = track->color; + sh_v->spherical = track->spherical; done: demux_add_sh_stream(demuxer, sh); diff --git a/demux/stheader.h b/demux/stheader.h index 04f8198df4..a0820f55b7 100644 --- a/demux/stheader.h +++ b/demux/stheader.h @@ -22,7 +22,7 @@ #include "common/common.h" #include "audio/chmap.h" -#include "video/csputils.h" +#include "video/mp_image.h" struct MPOpts; struct demuxer; @@ -93,6 +93,7 @@ struct mp_codec_params { int rotate; // intended display rotation, in degrees, [0, 359] int stereo_mode; // mp_stereo3d_mode (0 if none/unknown) struct mp_colorspace color; // colorspace info where available + struct mp_spherical_params spherical; // STREAM_VIDEO + STREAM_AUDIO int bits_per_coded_sample; diff --git a/video/decode/dec_video.c b/video/decode/dec_video.c index 8211d1f3b2..04e428246b 100644 --- a/video/decode/dec_video.c +++ b/video/decode/dec_video.c @@ -244,6 +244,10 @@ static void fix_image_params(struct dec_video *d_video, p.color.sig_peak = 0.0; } + p.spherical = c->spherical; + if (p.spherical.type == MP_SPHERICAL_AUTO) + p.spherical.type = MP_SPHERICAL_NONE; + // Guess missing colorspace fields from metadata. This guarantees all // fields are at least set to legal values afterwards. mp_image_params_guess_csp(&p); diff --git a/video/filter/vf.c b/video/filter/vf.c index a126007498..0db6f2a286 100644 --- a/video/filter/vf.c +++ b/video/filter/vf.c @@ -224,7 +224,7 @@ void vf_print_filter_chain(struct vf_chain *c, int msglevel, return; for (vf_instance_t *f = c->first; f; f = f->next) { - char b[128] = {0}; + char b[256] = {0}; mp_snprintf_cat(b, sizeof(b), " [%s] ", f->full_name); if (f->label) mp_snprintf_cat(b, sizeof(b), "\"%s\" ", f->label); diff --git a/video/filter/vf_format.c b/video/filter/vf_format.c index 1953b61ab6..581bbe332f 100644 --- a/video/filter/vf_format.c +++ b/video/filter/vf_format.c @@ -19,6 +19,7 @@ #include <stdlib.h> #include <string.h> #include <inttypes.h> +#include <math.h> #include <libavutil/rational.h> @@ -46,6 +47,8 @@ struct vf_priv_s { int rotate; int dw, dh; double dar; + int spherical; + float spherical_ref_angles[3]; }; static bool is_compatible(int fmt1, int fmt2) @@ -127,6 +130,13 @@ static int reconfig(struct vf_instance *vf, struct mp_image_params *in, dsize = av_d2q(p->dar, INT_MAX); mp_image_params_set_dsize(out, dsize.num, dsize.den); + if (p->spherical) + out->spherical.type = p->spherical; + for (int n = 0; n < 3; n++) { + if (isfinite(p->spherical_ref_angles[n])) + out->spherical.ref_angles[n] = p->spherical_ref_angles[n]; + } + // Make sure the user-overrides are consistent (no RGB csp for YUV, etc.). mp_image_params_guess_csp(out); @@ -165,6 +175,10 @@ static const m_option_t vf_opts_fields[] = { OPT_INT("dw", dw, 0), OPT_INT("dh", dh, 0), OPT_DOUBLE("dar", dar, 0), + OPT_CHOICE_C("spherical", spherical, 0, mp_spherical_names), + OPT_FLOAT("spherical-yaw", spherical_ref_angles[0], 0), + OPT_FLOAT("spherical-pitch", spherical_ref_angles[1], 0), + OPT_FLOAT("spherical-roll", spherical_ref_angles[2], 0), OPT_REMOVED("outputlevels", "use the --video-output-levels global option"), OPT_REMOVED("peak", "use sig-peak instead (changed value scale!)"), {0} @@ -178,5 +192,6 @@ const vf_info_t vf_info_format = { .options = vf_opts_fields, .priv_defaults = &(const struct vf_priv_s){ .rotate = -1, + .spherical_ref_angles = {NAN, NAN, NAN}, }, }; diff --git a/video/mp_image.c b/video/mp_image.c index 765289f8ff..45e5330947 100644 --- a/video/mp_image.c +++ b/video/mp_image.c @@ -41,6 +41,14 @@ #define HAVE_OPAQUE_REF (LIBAVUTIL_VERSION_MICRO >= 100 && \ LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(55, 47, 100)) +const struct m_opt_choice_alternatives mp_spherical_names[] = { + {"auto", MP_SPHERICAL_AUTO}, + {"none", MP_SPHERICAL_NONE}, + {"unknown", MP_SPHERICAL_UNKNOWN}, + {"equirect", MP_SPHERICAL_EQUIRECTANGULAR}, + {0} +}; + // Determine strides, plane sizes, and total required size for an image // allocation. Returns total size on success, <0 on error. Unused planes // have out_stride/out_plane_size to 0, and out_plane_offset set to -1 up @@ -525,6 +533,7 @@ void mp_image_copy_attributes(struct mp_image *dst, struct mp_image *src) dst->params.color.levels = src->params.color.levels; dst->params.chroma_location = src->params.chroma_location; } + dst->params.spherical = src->params.spherical; mp_image_params_guess_csp(&dst->params); // ensure colorspace consistency if ((dst->fmt.flags & MP_IMGFLAG_PAL) && (src->fmt.flags & MP_IMGFLAG_PAL)) { if (dst->planes[1] && src->planes[1]) { @@ -657,6 +666,12 @@ char *mp_image_params_to_str_buf(char *b, size_t bs, MP_STEREO3D_NAME_DEF(p->stereo_in, "?"), MP_STEREO3D_NAME_DEF(p->stereo_out, "?")); } + if (p->spherical.type != MP_SPHERICAL_NONE) { + const float *a = p->spherical.ref_angles; + mp_snprintf_cat(b, bs, " (%s %f/%f/%f)", + m_opt_choice_str(mp_spherical_names, p->spherical.type), + a[0], a[1], a[2]); + } } else { snprintf(b, bs, "???"); } @@ -691,6 +706,16 @@ bool mp_image_params_valid(const struct mp_image_params *p) return true; } +static bool mp_spherical_equal(const struct mp_spherical_params *p1, + const struct mp_spherical_params *p2) +{ + for (int n = 0; n < 3; n++) { + if (p1->ref_angles[n] != p2->ref_angles[n]) + return false; + } + return p1->type == p2->type; +} + bool mp_image_params_equal(const struct mp_image_params *p1, const struct mp_image_params *p2) { @@ -702,7 +727,8 @@ bool mp_image_params_equal(const struct mp_image_params *p1, p1->chroma_location == p2->chroma_location && p1->rotate == p2->rotate && p1->stereo_in == p2->stereo_in && - p1->stereo_out == p2->stereo_out; + p1->stereo_out == p2->stereo_out && + mp_spherical_equal(&p1->spherical, &p2->spherical); } // Set most image parameters, but not image format or size. diff --git a/video/mp_image.h b/video/mp_image.h index 640e2709e9..53b25c5999 100644 --- a/video/mp_image.h +++ b/video/mp_image.h @@ -36,6 +36,20 @@ #define MP_IMGFIELD_REPEAT_FIRST 0x04 #define MP_IMGFIELD_INTERLACED 0x20 +enum mp_spherical_type { + MP_SPHERICAL_AUTO = 0, + MP_SPHERICAL_NONE, // normal video + MP_SPHERICAL_UNKNOWN, // unknown projection + MP_SPHERICAL_EQUIRECTANGULAR, // (untiled) +}; + +extern const struct m_opt_choice_alternatives mp_spherical_names[]; + +struct mp_spherical_params { + enum mp_spherical_type type; + float ref_angles[3]; // yaw/pitch/roll, refer to AVSphericalMapping +}; + // Describes image parameters that usually stay constant. // New fields can be added in the future. Code changing the parameters should // usually copy the whole struct, so that fields added later will be preserved. @@ -50,6 +64,7 @@ struct mp_image_params { 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 + struct mp_spherical_params spherical; }; /* Memory management: @@ -144,7 +159,7 @@ void mp_image_params_guess_csp(struct mp_image_params *params); char *mp_image_params_to_str_buf(char *b, size_t bs, const struct mp_image_params *p); -#define mp_image_params_to_str(p) mp_image_params_to_str_buf((char[99]){0}, 99, p) +#define mp_image_params_to_str(p) mp_image_params_to_str_buf((char[256]){0}, 256, p) bool mp_image_params_valid(const struct mp_image_params *p); bool mp_image_params_equal(const struct mp_image_params *p1, @@ -481,6 +481,12 @@ FFmpeg/Libav libraries. You need at least {0}. Aborting.".format(libav_versions_ 'func': check_statement('libavutil/frame.h', 'AV_FRAME_DATA_ICC_PROFILE', use='libav'), + }, { + 'name': 'avutil-spherical', + 'desc': 'libavutil spherical side data', + 'func': check_statement('libavutil/spherical.h', + 'AV_SPHERICAL_EQUIRECTANGULAR', + use='libav'), }, ] |