From 820544cfbcc8a9baf7f87d12701c9ac6cbd02258 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20Michaj=C5=82ow?= Date: Wed, 23 Sep 2026 16:16:47 +0200 Subject: [PATCH 1/2] csputils: share the AVStereo3D to mp_stereo3d_mode mapping Move it out of mp_image_from_av_frame() next to mp_stereo3d_names[], so demuxers can map stream side data the same way. --- video/csputils.c | 24 ++++++++++++++++++++++++ video/csputils.h | 3 +++ video/mp_image.c | 25 +------------------------ 3 files changed, 28 insertions(+), 24 deletions(-) diff --git a/video/csputils.c b/video/csputils.c index 58c008a943080..12776c4d55851 100644 --- a/video/csputils.c +++ b/video/csputils.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include "mp_image.h" @@ -154,6 +155,29 @@ const struct m_opt_choice_alternatives mp_stereo3d_names[] = { {0} }; +enum mp_stereo3d_mode mp_stereo3d_from_av(const struct AVStereo3D *s3d) +{ + bool inv = s3d->flags & AV_STEREO3D_FLAG_INVERT; + switch (s3d->type) { + case AV_STEREO3D_SIDEBYSIDE: + case AV_STEREO3D_SIDEBYSIDE_QUINCUNX: + return inv ? MP_STEREO3D_SBS2R : MP_STEREO3D_SBS2L; + case AV_STEREO3D_TOPBOTTOM: + return inv ? MP_STEREO3D_AB2R : MP_STEREO3D_AB2L; + case AV_STEREO3D_CHECKERBOARD: + return inv ? MP_STEREO3D_CHECKR : MP_STEREO3D_CHECKL; + case AV_STEREO3D_LINES: + return inv ? MP_STEREO3D_IRR : MP_STEREO3D_IRL; + case AV_STEREO3D_COLUMNS: + return inv ? MP_STEREO3D_ICR : MP_STEREO3D_ICL; + case AV_STEREO3D_FRAMESEQUENCE: + return inv ? MP_STEREO3D_AR : MP_STEREO3D_AL; + default: + // AV_STEREO3D_2D and types mpv has no mode for. + return MP_STEREO3D_MONO; + } +} + void mp_get_3d_side_by_side(int stereo_mode, int div[2]) { div[0] = div[1] = 1; diff --git a/video/csputils.h b/video/csputils.h index 4ed18f1ab244f..b010bacc099a4 100644 --- a/video/csputils.h +++ b/video/csputils.h @@ -69,6 +69,9 @@ enum mp_stereo3d_mode { extern const struct m_opt_choice_alternatives mp_stereo3d_names[]; +struct AVStereo3D; +enum mp_stereo3d_mode mp_stereo3d_from_av(const struct AVStereo3D *s3d); + #define MP_STEREO3D_NAME_DEF(x, def) m_opt_choice_str_def(mp_stereo3d_names, x, def) // Number of screen divisions per axis (div[0]=x, div[1]=y) for the given 3D mode diff --git a/video/mp_image.c b/video/mp_image.c index 5a5a84f69873a..5eee406acacc4 100644 --- a/video/mp_image.c +++ b/video/mp_image.c @@ -1080,29 +1080,6 @@ void mp_image_params_guess_csp(struct mp_image_params *params) } } -static enum mp_stereo3d_mode stereo3d_from_av(const AVStereo3D *s3d) -{ - bool inv = s3d->flags & AV_STEREO3D_FLAG_INVERT; - switch (s3d->type) { - case AV_STEREO3D_SIDEBYSIDE: - case AV_STEREO3D_SIDEBYSIDE_QUINCUNX: - return inv ? MP_STEREO3D_SBS2R : MP_STEREO3D_SBS2L; - case AV_STEREO3D_TOPBOTTOM: - return inv ? MP_STEREO3D_AB2R : MP_STEREO3D_AB2L; - case AV_STEREO3D_CHECKERBOARD: - return inv ? MP_STEREO3D_CHECKR : MP_STEREO3D_CHECKL; - case AV_STEREO3D_LINES: - return inv ? MP_STEREO3D_IRR : MP_STEREO3D_IRL; - case AV_STEREO3D_COLUMNS: - return inv ? MP_STEREO3D_ICR : MP_STEREO3D_ICL; - case AV_STEREO3D_FRAMESEQUENCE: - return inv ? MP_STEREO3D_AR : MP_STEREO3D_AL; - default: - // AV_STEREO3D_2D and types mpv has no mode for. - return MP_STEREO3D_MONO; - } -} - // Create a new mp_image reference to av_frame. struct mp_image *mp_image_from_av_frame(struct AVFrame *src) { @@ -1157,7 +1134,7 @@ struct mp_image *mp_image_from_av_frame(struct AVFrame *src) sd = av_frame_get_side_data(src, AV_FRAME_DATA_STEREO3D); if (sd) - dst->params.stereo3d = stereo3d_from_av((const AVStereo3D *)sd->data); + dst->params.stereo3d = mp_stereo3d_from_av((const AVStereo3D *)sd->data); if (src->opaque_ref) { struct mp_image_params *p = (void *)src->opaque_ref->data; From 9700316c800001f4bf01b064a573c50b1520867c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20Michaj=C5=82ow?= Date: Wed, 23 Sep 2026 16:16:48 +0200 Subject: [PATCH 2/2] demux_lavf: read the stereo 3D mode from the stream side data libavcodec maps the stream side data onto every frame it allocates through ff_get_buffer(), so this changes nothing for most decoders. Decoders that build their frames by hand, v4l2m2m and rkmpp, never see it, and the container fallback in fix_image_params() is all they get. This also matches demux_mkv, which fills the field from StereoMode. --- demux/demux_lavf.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/demux/demux_lavf.c b/demux/demux_lavf.c index 739babf826c5d..9536e62d85c4c 100644 --- a/demux/demux_lavf.c +++ b/demux/demux_lavf.c @@ -37,6 +37,7 @@ #include #include #include +#include #include "audio/chmap_avchannel.h" @@ -58,6 +59,7 @@ #include "options/m_option.h" #include "options/options.h" #include "options/path.h" +#include "video/csputils.h" #define INITIAL_PROBE_SIZE STREAM_BUFFER_SIZE #define PROBE_BUF_SIZE (10 * 1024 * 1024) @@ -783,6 +785,9 @@ static void handle_new_stream(demuxer_t *demuxer, int i) sh->codec->rotate = (((int)(-r) % 360) + 360) % 360; } + if ((sd = mp_av_stream_get_side_data(st, AV_PKT_DATA_STEREO3D))) + sh->codec->stereo_mode = mp_stereo3d_from_av((const AVStereo3D *)sd); + if ((sd = mp_av_stream_get_side_data(st, AV_PKT_DATA_DOVI_CONF))) { const AVDOVIDecoderConfigurationRecord *cfg = (void *) sd; MP_VERBOSE(demuxer, "Found Dolby Vision config record: profile "