[PR] Add stereo3d option (PR #24300)
Jun Zhao via ffmpeg-devel <[email protected]>
| Newsgroups | gmane.comp.video.ffmpeg.devel |
|---|---|
| Message-ID | <[email protected]> |
PR #24300 opened by Jun Zhao (mypopydev) URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24300 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24300.patch Add a per-stream output option -stereo3d that injects packed Stereo 3D side data so muxers can write their native layout metadata from sources that have none (PNG sequences and similar). With -strict unofficial, MP4 gets Google st3d; MOV still writes Apple vexu eyes only (no st3d on MOV in this series); Matroska gets StereoMode. The series also warns when MP4 skips st3d/sv3d under default strictness, and keeps a more specific st3d type when merging vexu eyes so dual-box files round-trip in ffprobe. >From c68bd52ceb92c240e2d8bcd5fe2e6831886916fd Mon Sep 17 00:00:00 2001 From: Jun Zhao <[email protected]> Date: Fri, 28 Aug 2026 10:31:44 +0800 Subject: [PATCH 1/6] fftools/ffmpeg: add -stereo3d per-stream output option Sources such as PNG sequences have no stereoscopic metadata, so there was no CLI way to write container layout tags without an external post-processor. Inject AV_PKT_DATA_STEREO3D onto the output stream after bitstream filters and before write_header. A bare -stereo3d applies to video and is ignored on other types; an explicit specifier on a non-video stream is rejected. Fixes: #24269 Reported-by: optozorax Signed-off-by: Jun Zhao <[email protected]> --- fftools/ffmpeg.h | 1 + fftools/ffmpeg_mux.c | 22 ++++++++++ fftools/ffmpeg_mux.h | 3 ++ fftools/ffmpeg_mux_init.c | 92 ++++++++++++++++++++++++++++++++++++++- fftools/ffmpeg_opt.c | 3 ++ 5 files changed, 120 insertions(+), 1 deletion(-) diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h index c403acdb59..d3aa191e23 100644 --- a/fftools/ffmpeg.h +++ b/fftools/ffmpeg.h @@ -203,6 +203,7 @@ typedef struct OptionsContext { SpecifierOptList fps_mode; SpecifierOptList force_fps; SpecifierOptList frame_aspect_ratios; + SpecifierOptList stereo3ds; SpecifierOptList display_rotations; SpecifierOptList display_hflips; SpecifierOptList display_vflips; diff --git a/fftools/ffmpeg_mux.c b/fftools/ffmpeg_mux.c index b408b02f2a..0e546c286f 100644 --- a/fftools/ffmpeg_mux.c +++ b/fftools/ffmpeg_mux.c @@ -30,6 +30,7 @@ #include "libavutil/intreadwrite.h" #include "libavutil/log.h" #include "libavutil/mem.h" +#include "libavutil/stereo3d.h" #include "libavutil/time.h" #include "libavutil/timestamp.h" @@ -633,6 +634,27 @@ int of_stream_init(OutputFile *of, OutputStream *ost, if (ret < 0) return ret; + if (ms->stereo3d_set) { + AVCodecParameters *par = ost->st->codecpar; + AVStereo3D *stereo; + size_t size; + + stereo = av_stereo3d_alloc_size(&size); + if (!stereo) + return AVERROR(ENOMEM); + stereo->type = ms->stereo3d_type; + + if (av_packet_side_data_get(par->coded_side_data, par->nb_coded_side_data, + AV_PKT_DATA_STEREO3D)) + av_log(ost, AV_LOG_INFO, "Overriding existing stereoscopic 3D side data\n"); + + if (!av_packet_side_data_add(&par->coded_side_data, &par->nb_coded_side_data, + AV_PKT_DATA_STEREO3D, stereo, size, 0)) { + av_freep(&stereo); + return AVERROR(ENOMEM); + } + } + if (ms->stream_duration) { ost->st->duration = av_rescale_q(ms->stream_duration, ms->stream_duration_tb, ost->st->time_base); diff --git a/fftools/ffmpeg_mux.h b/fftools/ffmpeg_mux.h index f458cc882c..3d6686da02 100644 --- a/fftools/ffmpeg_mux.h +++ b/fftools/ffmpeg_mux.h @@ -87,6 +87,9 @@ typedef struct MuxStream { int force_fps; const char *apad; + + int stereo3d_set; + int stereo3d_type; } MuxStream; typedef struct Muxer { diff --git a/fftools/ffmpeg_mux_init.c b/fftools/ffmpeg_mux_init.c index f80b4427b4..4efee7e44f 100644 --- a/fftools/ffmpeg_mux_init.c +++ b/fftools/ffmpeg_mux_init.c @@ -47,6 +47,7 @@ #include "libavutil/opt.h" #include "libavutil/parseutils.h" #include "libavutil/pixdesc.h" +#include "libavutil/stereo3d.h" #define DEFAULT_PASS_LOGFILENAME_PREFIX "ffmpeg2pass" @@ -545,6 +546,86 @@ static enum AVPixelFormat pix_fmt_parse(OutputStream *ost, const char *name) return fmt; } +static int parse_stereo3d_type(void *logctx, const char *arg, int *type) +{ + static const struct { + const char *name; + int type; + } aliases[] = { + { "2d", AV_STEREO3D_2D }, + { "mono", AV_STEREO3D_2D }, + { "sbs", AV_STEREO3D_SIDEBYSIDE }, + { "sbsl", AV_STEREO3D_SIDEBYSIDE }, + { "tb", AV_STEREO3D_TOPBOTTOM }, + { "tbl", AV_STEREO3D_TOPBOTTOM }, + }; + static const enum AVStereo3DType v1_types[] = { + AV_STEREO3D_2D, + AV_STEREO3D_SIDEBYSIDE, + AV_STEREO3D_TOPBOTTOM, + }; + + for (int i = 0; i < FF_ARRAY_ELEMS(aliases); i++) { + if (!av_strcasecmp(arg, aliases[i].name)) { + *type = aliases[i].type; + return 0; + } + } + + for (int i = 0; i < FF_ARRAY_ELEMS(v1_types); i++) { + const char *name = av_stereo3d_type_name(v1_types[i]); + if (!av_strcasecmp(arg, name)) { + *type = v1_types[i]; + return 0; + } + } + + av_log(logctx, AV_LOG_ERROR, + "Invalid stereoscopic 3D layout '%s'. " + "Valid values are: 2d, mono, sbs, sbsl, side by side, " + "tb, tbl, top and bottom.\n", arg); + return AVERROR(EINVAL); +} + +static int check_stereo3d_leftovers(Muxer *mux, const OptionsContext *o) +{ + AVFormatContext *oc = mux->fc; + + for (int i = 0; i < o->stereo3ds.nb_opt; i++) { + const SpecifierOpt *so = &o->stereo3ds.opt[i]; + int matched_video = 0, matched_other = 0; + + /* Empty specifier applies to video only; ignore other stream types. */ + if (!so->specifier[0]) + continue; + + for (unsigned j = 0; j < oc->nb_streams; j++) { + AVStream *st = oc->streams[j]; + if (!stream_specifier_match(&so->stream_spec, oc, st, mux)) + continue; + if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) + matched_video++; + else + matched_other++; + } + + if (matched_other) { + av_log(mux, AV_LOG_ERROR, + "-stereo3d is only valid for video streams (specifier '%s').\n", + so->specifier); + return AVERROR(EINVAL); + } + if (!matched_video) { + av_log(mux, AV_LOG_ERROR, + "Stream specifier '%s' for -stereo3d matches no video streams.\n", + so->specifier); + return AVERROR(EINVAL); + } + } + + return 0; +} + static int new_stream_video(Muxer *mux, const OptionsContext *o, OutputStream *ost, int *keep_pix_fmt, enum VideoSyncMethod *vsync_method) @@ -553,6 +634,7 @@ static int new_stream_video(Muxer *mux, const OptionsContext *o, AVFormatContext *oc = mux->fc; AVStream *st; const char *frame_rate = NULL, *max_frame_rate = NULL, *frame_aspect_ratio = NULL; + const char *stereo3d = NULL; int ret = 0; st = ost->st; @@ -585,6 +667,14 @@ static int new_stream_video(Muxer *mux, const OptionsContext *o, ost->frame_aspect_ratio = q; } + opt_match_per_stream_str(ost, &o->stereo3ds, oc, st, &stereo3d); + if (stereo3d) { + ret = parse_stereo3d_type(ost, stereo3d, &ms->stereo3d_type); + if (ret < 0) + return ret; + ms->stereo3d_set = 1; + } + if (ost->enc) { AVCodecContext *video_enc = ost->enc->enc_ctx; const char *p = NULL, *fps_mode = NULL; @@ -2053,7 +2143,7 @@ static int create_streams(Muxer *mux, const OptionsContext *o) return AVERROR(EINVAL); } - return 0; + return check_stereo3d_leftovers(mux, o); } static int setup_sync_queues(Muxer *mux, AVFormatContext *oc, diff --git a/fftools/ffmpeg_opt.c b/fftools/ffmpeg_opt.c index fdbc0fdc13..fd7260c3f7 100644 --- a/fftools/ffmpeg_opt.c +++ b/fftools/ffmpeg_opt.c @@ -1853,6 +1853,9 @@ const OptionDef options[] = { { "aspect", OPT_TYPE_STRING, OPT_VIDEO | OPT_PERSTREAM | OPT_OUTPUT, { .off = OFFSET(frame_aspect_ratios) }, "set aspect ratio (4:3, 16:9 or 1.3333, 1.7777)", "aspect" }, + { "stereo3d", OPT_TYPE_STRING, OPT_VIDEO | OPT_PERSTREAM | OPT_OUTPUT, + { .off = OFFSET(stereo3ds) }, + "set stereoscopic 3D layout metadata (does not rearrange pixels)", "layout" }, { "pix_fmt", OPT_TYPE_STRING, OPT_VIDEO | OPT_EXPERT | OPT_PERSTREAM | OPT_INPUT | OPT_OUTPUT, { .off = OFFSET(frame_pix_fmts) }, "set pixel format", "format" }, -- 2.52.0 >From aefc1763c5099e954a326a14720c1e4f581364ef Mon Sep 17 00:00:00 2001 From: Jun Zhao <[email protected]> Date: Fri, 28 Aug 2026 10:31:53 +0800 Subject: [PATCH 2/6] avformat/movenc: warn when st3d/sv3d skipped due to strict compliance Those boxes are written only with -strict unofficial. Fetch the side data before that gate so a warning is logged only when a box would have been written, matching dvcC/hvcE. Whether the box is written is unchanged. Signed-off-by: Jun Zhao <[email protected]> --- libavformat/movenc.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/libavformat/movenc.c b/libavformat/movenc.c index 4c7868c5f8..380f18a859 100644 --- a/libavformat/movenc.c +++ b/libavformat/movenc.c @@ -2994,17 +2994,21 @@ static int mov_write_video_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContex mov_write_amve_tag(pb, track); } - if (track->mode == MODE_MP4 && mov->fc->strict_std_compliance <= FF_COMPLIANCE_UNOFFICIAL) { + if (track->mode == MODE_MP4) { const AVPacketSideData *stereo_3d = av_packet_side_data_get(track->st->codecpar->coded_side_data, track->st->codecpar->nb_coded_side_data, AV_PKT_DATA_STEREO3D); const AVPacketSideData *spherical_mapping = av_packet_side_data_get(track->st->codecpar->coded_side_data, track->st->codecpar->nb_coded_side_data, AV_PKT_DATA_SPHERICAL); - if (stereo_3d) + if (stereo_3d && mov->fc->strict_std_compliance <= FF_COMPLIANCE_UNOFFICIAL) mov_write_st3d_tag(s, pb, (AVStereo3D*)stereo_3d->data); - if (spherical_mapping) + else if (stereo_3d) + av_log(s, AV_LOG_WARNING, "Not writing 'st3d' box. Requires -strict unofficial.\n"); + if (spherical_mapping && mov->fc->strict_std_compliance <= FF_COMPLIANCE_UNOFFICIAL) mov_write_sv3d_tag(mov->fc, pb, (AVSphericalMapping*)spherical_mapping->data); + else if (spherical_mapping) + av_log(s, AV_LOG_WARNING, "Not writing 'sv3d' box. Requires -strict unofficial.\n"); } if (track->mode == MODE_MOV || (track->mode == MODE_MP4 && -- 2.52.0 >From 1a787eca6cf62da68b794cc5a807397f51dd8c2d Mon Sep 17 00:00:00 2001 From: Jun Zhao <[email protected]> Date: Fri, 28 Aug 2026 10:31:53 +0800 Subject: [PATCH 3/6] avformat/mov: keep st3d type when merging vexu eyes vexu eyes/stri only records packed vs single-eye, not SBS/TB. Writing both boxes (MP4 with -strict unofficial) let that UNSPEC type overwrite the layout already parsed from st3d. Keep the more specific type so the file round-trips in ffprobe. Signed-off-by: Jun Zhao <[email protected]> --- libavformat/mov.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/libavformat/mov.c b/libavformat/mov.c index f53ce693f8..f6428c57e4 100644 --- a/libavformat/mov.c +++ b/libavformat/mov.c @@ -7566,7 +7566,12 @@ static int mov_read_eyes(MOVContext *c, AVIOContext *pb, MOVAtom atom) } sc->stereo3d->flags = flags; - sc->stereo3d->type = type; + /* eyes/stri only records packed vs single-eye, not SBS/TB. Keep a more + * specific type already set by st3d. */ + if (type != AV_STEREO3D_UNSPEC) + sc->stereo3d->type = type; + else if (sc->stereo3d->type == AV_STEREO3D_2D) + sc->stereo3d->type = type; sc->stereo3d->view = view; sc->stereo3d->primary_eye = primary_eye; sc->stereo3d->baseline = baseline; -- 2.52.0 >From ae9264bb52f691a85682d8f6aca692004ee6375e Mon Sep 17 00:00:00 2001 From: Jun Zhao <[email protected]> Date: Fri, 28 Aug 2026 10:31:54 +0800 Subject: [PATCH 4/6] tests/fate: add a Matroska -stereo3d encode test Encode vsynth through mpeg4 with -stereo3d:v sbsl and check that ffprobe reports side-by-side packed Stereo 3D side data. Signed-off-by: Jun Zhao <[email protected]> --- tests/fate/matroska.mak | 8 ++++++++ tests/ref/fate/matroska-stereo3d-sbs | 22 ++++++++++++++++++++++ 2 files changed, 30 insertions(+) create mode 100644 tests/ref/fate/matroska-stereo3d-sbs diff --git a/tests/fate/matroska.mak b/tests/fate/matroska.mak index 6a98845ca2..63c38a1043 100644 --- a/tests/fate/matroska.mak +++ b/tests/fate/matroska.mak @@ -339,6 +339,14 @@ fate-matroska-reenc-delete-metadata-filter-output: CMD = transcode matroska $(TA FATE_MATROSKA_FFMPEG_FFPROBE-$(call TRANSCODE, MPEG2VIDEO HEVC, NUT MATROSKA, SCALE_FILTER) += fate-matroska-reenc-chapter-nofilter fate-matroska-reenc-chapter-nofilter: CMD = transcode matroska $(TARGET_SAMPLES)/mkv/hdr10tags-both.mkv nut "-map 0:v:0 -vf scale=iw:ih -c:v mpeg2video -bitexact -metadata:c:0 NUMBER_OF_FRAMES=test" "-c copy -t 0.1" "-show_entries chapter_tags" "" "" "" null +# Encode-path injection of -stereo3d into Matroska StereoMode via side data. +FATE_MATROSKA_FFMPEG_FFPROBE-$(call ALLYES, FILE_PROTOCOL RAWVIDEO_DEMUXER MPEG4_ENCODER MATROSKA_MUXER MATROSKA_DEMUXER) \ + += fate-matroska-stereo3d-sbs +fate-matroska-stereo3d-sbs: tests/data/vsynth1.yuv +fate-matroska-stereo3d-sbs: CMD = transcode rawvideo $(TARGET_PATH)/tests/data/vsynth1.yuv matroska \ + "-c:v mpeg4 -qscale:v 10 -stereo3d:v sbsl -frames:v 2" \ + "-c:v copy" "-show_entries stream_side_data_list" "" "" "-s 352x288 -pix_fmt yuv420p" + FATE_SAMPLES_AVCONV += $(FATE_MATROSKA-yes) FATE_SAMPLES_FFPROBE += $(FATE_MATROSKA_FFPROBE-yes) FATE_SAMPLES_FFMPEG_FFPROBE += $(FATE_MATROSKA_FFMPEG_FFPROBE-yes) diff --git a/tests/ref/fate/matroska-stereo3d-sbs b/tests/ref/fate/matroska-stereo3d-sbs new file mode 100644 index 0000000000..f4d5256037 --- /dev/null +++ b/tests/ref/fate/matroska-stereo3d-sbs @@ -0,0 +1,22 @@ +16938e7e91ea9492eef3654d3db9af57 *tests/data/fate/matroska-stereo3d-sbs.matroska +38205 tests/data/fate/matroska-stereo3d-sbs.matroska +#extradata 0: 30, 0x47ab0576 +#tb 0: 1/1000 +#media_type 0: video +#codec_id 0: mpeg4 +#dimensions 0: 352x288 +#sar 0: 1/1 +0, 0, 0, 40, 27837, 0xd9809b60 +0, 40, 40, 40, 9806, 0xbebc2826, F=0x0 +[STREAM] +[SIDE_DATA] +side_data_type=Stereo 3D +type=side by side +inverted=0 +view=packed +primary_eye=none +baseline=0 +horizontal_disparity_adjustment=0/1 +horizontal_field_of_view=0/1 +[/SIDE_DATA] +[/STREAM] -- 2.52.0 >From 4c17c2239cc1ef3d93d2b95c33af939698fdc924 Mon Sep 17 00:00:00 2001 From: Jun Zhao <[email protected]> Date: Fri, 28 Aug 2026 10:31:54 +0800 Subject: [PATCH 5/6] tests/fate: add an MP4 -stereo3d encode test Encode vsynth through mpeg4 into MP4 with -strict unofficial and -stereo3d:v sbsl, and check that ffprobe round-trips side-by-side packed Stereo 3D side data. Signed-off-by: Jun Zhao <[email protected]> --- tests/fate/mov.mak | 8 ++++++++ tests/ref/fate/mov-stereo3d-sbs-mp4 | 22 ++++++++++++++++++++++ 2 files changed, 30 insertions(+) create mode 100644 tests/ref/fate/mov-stereo3d-sbs-mp4 diff --git a/tests/fate/mov.mak b/tests/fate/mov.mak index 1a81962626..ad80a39470 100644 --- a/tests/fate/mov.mak +++ b/tests/fate/mov.mak @@ -408,6 +408,14 @@ FATE_MOV_FFMPEG_SAMPLES-$(call REMUX, MP4 MOV, AAC_PARSER) \ += fate-mov-mp4-edst-remainder fate-mov-mp4-edst-remainder: CMD = stream_remux mov $(TARGET_SAMPLES)/audiomatch/tones_fdkaac_44100_stereo_aac_lc.m4a "" mp4 "" "" "-c:a copy" +# Encode-path injection of -stereo3d into MP4 st3d (requires unofficial). +FATE_MOV_FFMPEG_FFPROBE-$(call ALLYES, FILE_PROTOCOL RAWVIDEO_DEMUXER MPEG4_ENCODER MP4_MUXER MOV_DEMUXER) \ + += fate-mov-stereo3d-sbs-mp4 +fate-mov-stereo3d-sbs-mp4: tests/data/vsynth1.yuv +fate-mov-stereo3d-sbs-mp4: CMD = transcode rawvideo $(TARGET_PATH)/tests/data/vsynth1.yuv mp4 \ + "-c:v mpeg4 -qscale:v 10 -stereo3d:v sbsl -strict unofficial -frames:v 2" \ + "-c:v copy" "-show_entries stream_side_data_list" "" "" "-s 352x288 -pix_fmt yuv420p" + # format-level branding: major_brand, minor_version, compatible_brands should be deleted on re-encode FATE_MOV_FFMPEG_FFPROBE-$(call ENCDEC, AAC AAC, NUT MOV) += fate-mov-reenc-delete-format-metadata fate-mov-reenc-delete-format-metadata: CMD = transcode mov $(TARGET_SAMPLES)/cover_art/Owner-iTunes_9.0.3.15.m4a nut "-map 0:a:0 -c:a aac -bitexact -t 0.1" "-c copy -t 0.1" "-show_entries format_tags" "" "" "" null diff --git a/tests/ref/fate/mov-stereo3d-sbs-mp4 b/tests/ref/fate/mov-stereo3d-sbs-mp4 new file mode 100644 index 0000000000..68bae7ce2a --- /dev/null +++ b/tests/ref/fate/mov-stereo3d-sbs-mp4 @@ -0,0 +1,22 @@ +bc24ade91fb35a16a47dcb5664a36701 *tests/data/fate/mov-stereo3d-sbs-mp4.mp4 +38520 tests/data/fate/mov-stereo3d-sbs-mp4.mp4 +#extradata 0: 30, 0x47ab0576 +#tb 0: 1/12800 +#media_type 0: video +#codec_id 0: mpeg4 +#dimensions 0: 352x288 +#sar 0: 1/1 +0, 0, 0, 512, 27837, 0xd9809b60 +0, 512, 512, 512, 9806, 0xbebc2826, F=0x0 +[STREAM] +[SIDE_DATA] +side_data_type=Stereo 3D +type=side by side +inverted=0 +view=packed +primary_eye=none +baseline=0 +horizontal_disparity_adjustment=0/1 +horizontal_field_of_view=0/1 +[/SIDE_DATA] +[/STREAM] -- 2.52.0 >From da25a23aed39c4ac8833bf67682e7b7c712e78dd Mon Sep 17 00:00:00 2001 From: Jun Zhao <[email protected]> Date: Fri, 28 Aug 2026 10:31:54 +0800 Subject: [PATCH 6/6] doc: document the -stereo3d option Describe the CLI values, that the option writes layout metadata rather than rearranging pixels, and how MP4/MOV/Matroska consume the resulting side data. Signed-off-by: Jun Zhao <[email protected]> --- doc/ffmpeg.texi | 41 +++++++++++++++++++++++++++++++++++++++++ doc/muxers.texi | 18 ++++++++++++++++++ 2 files changed, 59 insertions(+) diff --git a/doc/ffmpeg.texi b/doc/ffmpeg.texi index 1cbb1ccbdd..e4fb3cbec3 100644 --- a/doc/ffmpeg.texi +++ b/doc/ffmpeg.texi @@ -1590,6 +1590,47 @@ If used together with @option{-vcodec copy}, it will affect the aspect ratio stored at container level, but not the aspect ratio stored in encoded frames, if it exists. +@item -stereo3d[:@var{stream_specifier}] @var{layout} (@emph{output,per-stream}) +Set stereoscopic 3D layout metadata on the output stream. This does +@emph{not} rearrange pixels; use @option{-vf stereo3d} for that. + +The metadata is stored as @code{AV_PKT_DATA_STEREO3D} side data on the +output stream. Muxers that already consume that side data will write the +corresponding container boxes or elements, including: + +@itemize +@item +MP4 Google spatial-media @code{st3d} (requires @option{-strict unofficial}) +@item +QuickTime MOV Apple @code{vexu} eyes (no @code{st3d}) +@item +Matroska @code{StereoMode} (unless @option{-metadata stereo_mode} is also set, +in which case metadata still takes priority) +@end itemize + +@var{layout} is case-insensitive. The following values are accepted: + +@table @samp +@item 2d +@itemx mono +Monoscopic video. +@item sbs +@itemx sbsl +@itemx side by side +Side-by-side, left eye on the left. +@item tb +@itemx tbl +@itemx top and bottom +Top-and-bottom, left eye on top. +@end table + +Inverted layouts such as @samp{sbsr} are not supported. An empty stream +specifier applies to video streams only and is ignored for audio and +other types. An explicit specifier on a non-video stream (for example +@option{-stereo3d:a}) is an error. + +Recommended form: @option{-stereo3d:v sbsl}. + @item -display_rotation[:@var{stream_specifier}] @var{rotation} (@emph{input,per-stream}) Set video rotation metadata. diff --git a/doc/muxers.texi b/doc/muxers.texi index 99584e2b8d..33545fcb7d 100644 --- a/doc/muxers.texi +++ b/doc/muxers.texi @@ -377,6 +377,21 @@ on MPEG-4 Part 14 format with a few incompatible variants, used to play files on PlayStation devices. @end table +@subsection Stereoscopic 3D + +When the output stream has stereoscopic 3D side data (see the +@option{-stereo3d} option), these muxers write: + +@itemize +@item +MP4: Google spatial-media @code{st3d} and Apple @code{vexu}, both +requiring @option{-strict unofficial}. A missing unofficial compliance +level skips those boxes and logs a warning naming the box that was not +written. +@item +MOV: Apple @code{vexu} eyes only. @code{st3d} is not written. +@end itemize + @subsection Fragmentation The @samp{mov}, @samp{mp4}, and @samp{ismv} muxers support @@ -2867,6 +2882,9 @@ French). @item stereo_mode Set stereo 3D video layout of two views in a single video track. +If this metadata is unset, the muxer falls back to stereoscopic +side data on the stream (see the @option{-stereo3d} option). +Metadata takes priority when both are present. The following values are recognized: @table @samp -- 2.52.0 _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]