[FFmpeg-cvslog] avfilter/vf_v360: implement stereo 3D support

Paul B Mahol git at videolan.org
Sat Sep 14 20:56:18 EEST 2019


ffmpeg | branch: master | Paul B Mahol <onemda at gmail.com> | Sat Sep 14 18:16:02 2019 +0200| [45bb80dccc558a38a3539496575694995b38ff64] | committer: Paul B Mahol

avfilter/vf_v360: implement stereo 3D support

> http://git.videolan.org/gitweb.cgi/ffmpeg.git/?a=commit;h=45bb80dccc558a38a3539496575694995b38ff64
---

 doc/filters.texi      |  15 +++++
 libavfilter/v360.h    |  14 +++++
 libavfilter/vf_v360.c | 157 ++++++++++++++++++++++++++++++++++++--------------
 3 files changed, 142 insertions(+), 44 deletions(-)

diff --git a/doc/filters.texi b/doc/filters.texi
index b2a955113c..2995e9041e 100644
--- a/doc/filters.texi
+++ b/doc/filters.texi
@@ -18080,6 +18080,21 @@ Set the output video resolution.
 
 Default resolution depends on formats.
 
+ at item in_stereo
+ at item out_stereo
+Set the input/output stereo format.
+
+ at table @samp
+ at item 2d
+2D mono
+ at item sbs
+Side by side
+ at item tb
+Top bottom
+ at end table
+
+Default value is @b{@samp{2d}} for input and output format.
+
 @item yaw
 @item pitch
 @item roll
diff --git a/libavfilter/v360.h b/libavfilter/v360.h
index 11c1e27e4b..8e8799a89e 100644
--- a/libavfilter/v360.h
+++ b/libavfilter/v360.h
@@ -22,6 +22,13 @@
 #define AVFILTER_V360_H
 #include "avfilter.h"
 
+enum StereoFormats {
+    STEREO_2D,
+    STEREO_SBS,
+    STEREO_TB,
+    NB_STEREO_FMTS,
+};
+
 enum Projections {
     EQUIRECTANGULAR,
     CUBEMAP_3_2,
@@ -95,6 +102,8 @@ typedef struct V360Context {
     int out_cubemap_face_rotation[6];
     int rotation_order[3];
 
+    int in_stereo, out_stereo;
+
     float in_pad, out_pad;
 
     float yaw, pitch, roll;
@@ -108,6 +117,11 @@ typedef struct V360Context {
 
     float input_mirror_modifier[2];
 
+    int pr_width[4], pr_height[4];
+
+    int in_offset_w[4], in_offset_h[4];
+    int out_offset_w[4], out_offset_h[4];
+
     int planewidth[4], planeheight[4];
     int inplanewidth[4], inplaneheight[4];
     int uv_linesize[4];
diff --git a/libavfilter/vf_v360.c b/libavfilter/vf_v360.c
index 3be302d159..cb4f84d89d 100644
--- a/libavfilter/vf_v360.c
+++ b/libavfilter/vf_v360.c
@@ -90,6 +90,11 @@ static const AVOption v360_options[] = {
     {   "lanczos", "lanczos interpolation",                      0, AV_OPT_TYPE_CONST,  {.i64=LANCZOS},         0,                   0, FLAGS, "interp" },
     {         "w", "output width",                   OFFSET(width), AV_OPT_TYPE_INT,    {.i64=0},               0,           INT16_MAX, FLAGS, "w"},
     {         "h", "output height",                 OFFSET(height), AV_OPT_TYPE_INT,    {.i64=0},               0,           INT16_MAX, FLAGS, "h"},
+    { "in_stereo", "input stereo format",        OFFSET(in_stereo), AV_OPT_TYPE_INT,    {.i64=STEREO_2D},       0,    NB_STEREO_FMTS-1, FLAGS, "stereo" },
+    {"out_stereo", "output stereo format",      OFFSET(out_stereo), AV_OPT_TYPE_INT,    {.i64=STEREO_2D},       0,    NB_STEREO_FMTS-1, FLAGS, "stereo" },
+    {        "2d", "2d mono",                                    0, AV_OPT_TYPE_CONST,  {.i64=STEREO_2D},       0,                   0, FLAGS, "stereo" },
+    {       "sbs", "side by side",                               0, AV_OPT_TYPE_CONST,  {.i64=STEREO_SBS},      0,                   0, FLAGS, "stereo" },
+    {        "tb", "top bottom",                                 0, AV_OPT_TYPE_CONST,  {.i64=STEREO_TB},       0,                   0, FLAGS, "stereo" },
     { "in_forder", "input cubemap face order",   OFFSET(in_forder), AV_OPT_TYPE_STRING, {.str="rludfb"},        0,     NB_DIRECTIONS-1, FLAGS, "in_forder"},
     {"out_forder", "output cubemap face order", OFFSET(out_forder), AV_OPT_TYPE_STRING, {.str="rludfb"},        0,     NB_DIRECTIONS-1, FLAGS, "out_forder"},
     {   "in_frot", "input cubemap face rotation",  OFFSET(in_frot), AV_OPT_TYPE_STRING, {.str="000000"},        0,     NB_DIRECTIONS-1, FLAGS, "in_frot"},
@@ -222,25 +227,31 @@ static int remap##ws##_##bits##bit_slice(AVFilterContext *ctx, void *arg, int jo
     const AVFrame *in = td->in;                                                                            \
     AVFrame *out = td->out;                                                                                \
                                                                                                            \
-    for (int plane = 0; plane < s->nb_planes; plane++) {                                                   \
-        const int in_linesize  = in->linesize[plane];                                                      \
-        const int out_linesize = out->linesize[plane];                                                     \
-        const int uv_linesize = s->uv_linesize[plane];                                                     \
-        const uint8_t *src = in->data[plane];                                                              \
-        uint8_t *dst = out->data[plane];                                                                   \
-        const int width = s->planewidth[plane];                                                            \
-        const int height = s->planeheight[plane];                                                          \
+    for (int stereo = 0; stereo < 1 + s->out_stereo > STEREO_2D; stereo++) {                               \
+        for (int plane = 0; plane < s->nb_planes; plane++) {                                               \
+            const int in_linesize  = in->linesize[plane];                                                  \
+            const int out_linesize = out->linesize[plane];                                                 \
+            const int uv_linesize = s->uv_linesize[plane];                                                 \
+            const int in_offset_w = stereo ? s->in_offset_w[plane] : 0;                                    \
+            const int in_offset_h = stereo ? s->in_offset_h[plane] : 0;                                    \
+            const int out_offset_w = stereo ? s->out_offset_w[plane] : 0;                                  \
+            const int out_offset_h = stereo ? s->out_offset_h[plane] : 0;                                  \
+            const uint8_t *src = in->data[plane] + in_offset_h * in_linesize + in_offset_w * (bits >> 3);  \
+            uint8_t *dst = out->data[plane] + out_offset_h * out_linesize + out_offset_w * (bits >> 3);    \
+            const int width = s->pr_width[plane];                                                          \
+            const int height = s->pr_height[plane];                                                        \
                                                                                                            \
-        const int slice_start = (height *  jobnr     ) / nb_jobs;                                          \
-        const int slice_end   = (height * (jobnr + 1)) / nb_jobs;                                          \
+            const int slice_start = (height *  jobnr     ) / nb_jobs;                                      \
+            const int slice_end   = (height * (jobnr + 1)) / nb_jobs;                                      \
                                                                                                            \
-        for (int y = slice_start; y < slice_end; y++) {                                                    \
-            const unsigned map = s->map[plane];                                                            \
-            const uint16_t *u = s->u[map] + y * uv_linesize * ws * ws;                                     \
-            const uint16_t *v = s->v[map] + y * uv_linesize * ws * ws;                                     \
-            const int16_t *ker = s->ker[map] + y * uv_linesize * ws * ws;                                  \
+            for (int y = slice_start; y < slice_end; y++) {                                                \
+                const unsigned map = s->map[plane];                                                        \
+                const uint16_t *u = s->u[map] + y * uv_linesize * ws * ws;                                 \
+                const uint16_t *v = s->v[map] + y * uv_linesize * ws * ws;                                 \
+                const int16_t *ker = s->ker[map] + y * uv_linesize * ws * ws;                              \
                                                                                                            \
-            s->remap_line(dst + y * out_linesize, width, src, in_linesize, u, v, ker);                     \
+                s->remap_line(dst + y * out_linesize, width, src, in_linesize, u, v, ker);                 \
+            }                                                                                              \
         }                                                                                                  \
     }                                                                                                      \
                                                                                                            \
@@ -2119,12 +2130,12 @@ static inline void mirror(const float *modifier, float *vec)
 
 static int allocate_plane(V360Context *s, int sizeof_uv, int sizeof_ker, int p)
 {
-    s->u[p] = av_calloc(s->uv_linesize[p] * s->planeheight[p], sizeof_uv);
-    s->v[p] = av_calloc(s->uv_linesize[p] * s->planeheight[p], sizeof_uv);
+    s->u[p] = av_calloc(s->uv_linesize[p] * s->pr_height[p], sizeof_uv);
+    s->v[p] = av_calloc(s->uv_linesize[p] * s->pr_height[p], sizeof_uv);
     if (!s->u[p] || !s->v[p])
         return AVERROR(ENOMEM);
     if (sizeof_ker) {
-        s->ker[p] = av_calloc(s->uv_linesize[p] * s->planeheight[p], sizeof_ker);
+        s->ker[p] = av_calloc(s->uv_linesize[p] * s->pr_height[p], sizeof_ker);
         if (!s->ker[p])
             return AVERROR(ENOMEM);
     }
@@ -2158,6 +2169,8 @@ static int config_output(AVFilterLink *outlink)
     int elements;
     int err;
     int h, w;
+    int in_offset_h, in_offset_w;
+    int out_offset_h, out_offset_w;
     float hf, wf;
     float output_mirror_modifier[3];
     void (*in_transform)(const V360Context *s,
@@ -2229,36 +2242,68 @@ static int config_output(AVFilterLink *outlink)
         s->rotation_order[order] = rorder;
     }
 
+    switch (s->in_stereo) {
+    case STEREO_2D:
+        w = inlink->w;
+        h = inlink->h;
+        in_offset_w = in_offset_h = 0;
+        break;
+    case STEREO_SBS:
+        w = inlink->w / 2;
+        h = inlink->h;
+        in_offset_w = w;
+        in_offset_h = 0;
+        break;
+    case STEREO_TB:
+        w = inlink->w;
+        h = inlink->h / 2;
+        in_offset_w = 0;
+        in_offset_h = h;
+        break;
+    default:
+        av_assert0(0);
+    }
+
+    s->inplaneheight[1] = s->inplaneheight[2] = FF_CEIL_RSHIFT(h, desc->log2_chroma_h);
+    s->inplaneheight[0] = s->inplaneheight[3] = h;
+    s->inplanewidth[1]  = s->inplanewidth[2]  = FF_CEIL_RSHIFT(w, desc->log2_chroma_w);
+    s->inplanewidth[0]  = s->inplanewidth[3]  = w;
+
+    s->in_offset_h[1] = s->in_offset_h[2] = FF_CEIL_RSHIFT(in_offset_h, desc->log2_chroma_h);
+    s->in_offset_h[0] = s->in_offset_h[3] = in_offset_h;
+    s->in_offset_w[1] = s->in_offset_w[2] = FF_CEIL_RSHIFT(in_offset_w, desc->log2_chroma_w);
+    s->in_offset_w[0] = s->in_offset_w[3] = in_offset_w;
+
     switch (s->in) {
     case EQUIRECTANGULAR:
         in_transform = xyz_to_equirect;
         err = 0;
-        wf = inlink->w;
-        hf = inlink->h;
+        wf = w;
+        hf = h;
         break;
     case CUBEMAP_3_2:
         in_transform = xyz_to_cube3x2;
         err = prepare_cube_in(ctx);
-        wf = inlink->w / 3.f * 4.f;
-        hf = inlink->h;
+        wf = w / 3.f * 4.f;
+        hf = h;
         break;
     case CUBEMAP_1_6:
         in_transform = xyz_to_cube1x6;
         err = prepare_cube_in(ctx);
-        wf = inlink->w * 4.f;
-        hf = inlink->h / 3.f;
+        wf = w * 4.f;
+        hf = h / 3.f;
         break;
     case CUBEMAP_6_1:
         in_transform = xyz_to_cube6x1;
         err = prepare_cube_in(ctx);
-        wf = inlink->w / 3.f * 2.f;
-        hf = inlink->h * 2.f;
+        wf = w / 3.f * 2.f;
+        hf = h * 2.f;
         break;
     case EQUIANGULAR:
         in_transform = xyz_to_eac;
         err = prepare_eac_in(ctx);
-        wf = inlink->w;
-        hf = inlink->h / 9.f * 8.f;
+        wf = w;
+        hf = h / 9.f * 8.f;
         break;
     case FLAT:
         av_log(ctx, AV_LOG_ERROR, "Flat format is not accepted as input.\n");
@@ -2266,20 +2311,20 @@ static int config_output(AVFilterLink *outlink)
     case DUAL_FISHEYE:
         in_transform = xyz_to_dfisheye;
         err = 0;
-        wf = inlink->w;
-        hf = inlink->h;
+        wf = w;
+        hf = h;
         break;
     case BARREL:
         in_transform = xyz_to_barrel;
         err = 0;
-        wf = inlink->w / 5.f * 4.f;
-        hf = inlink->h;
+        wf = w / 5.f * 4.f;
+        hf = h;
         break;
     case STEREOGRAPHIC:
         in_transform = xyz_to_stereographic;
         err = 0;
-        wf = inlink->w;
-        hf = inlink->h / 2.f;
+        wf = w;
+        hf = h / 2.f;
         break;
     default:
         av_log(ctx, AV_LOG_ERROR, "Specified input format is not handled.\n");
@@ -2374,21 +2419,45 @@ static int config_output(AVFilterLink *outlink)
             return err;
     }
 
+    s->pr_height[1] = s->pr_height[2] = FF_CEIL_RSHIFT(h, desc->log2_chroma_h);
+    s->pr_height[0] = s->pr_height[3] = h;
+    s->pr_width[1]  = s->pr_width[2] = FF_CEIL_RSHIFT(w, desc->log2_chroma_w);
+    s->pr_width[0]  = s->pr_width[3] = w;
+
+    switch (s->out_stereo) {
+    case STEREO_2D:
+        out_offset_w = out_offset_h = 0;
+        break;
+    case STEREO_SBS:
+        out_offset_w = w;
+        out_offset_h = 0;
+        w *= 2;
+        break;
+    case STEREO_TB:
+        out_offset_w = 0;
+        out_offset_h = h;
+        h *= 2;
+        break;
+    default:
+        av_assert0(0);
+    }
+
+    s->out_offset_h[1] = s->out_offset_h[2] = FF_CEIL_RSHIFT(out_offset_h, desc->log2_chroma_h);
+    s->out_offset_h[0] = s->out_offset_h[3] = out_offset_h;
+    s->out_offset_w[1] = s->out_offset_w[2] = FF_CEIL_RSHIFT(out_offset_w, desc->log2_chroma_w);
+    s->out_offset_w[0] = s->out_offset_w[3] = out_offset_w;
+
     s->planeheight[1] = s->planeheight[2] = FF_CEIL_RSHIFT(h, desc->log2_chroma_h);
     s->planeheight[0] = s->planeheight[3] = h;
-    s->planewidth[1]  = s->planewidth[2] = FF_CEIL_RSHIFT(w, desc->log2_chroma_w);
-    s->planewidth[0]  = s->planewidth[3] = w;
+    s->planewidth[1]  = s->planewidth[2]  = FF_CEIL_RSHIFT(w, desc->log2_chroma_w);
+    s->planewidth[0]  = s->planewidth[3]  = w;
 
     for (int i = 0; i < 4; i++)
-        s->uv_linesize[i] = FFALIGN(s->planewidth[i], 8);
+        s->uv_linesize[i] = FFALIGN(s->pr_width[i], 8);
 
     outlink->h = h;
     outlink->w = w;
 
-    s->inplaneheight[1] = s->inplaneheight[2] = FF_CEIL_RSHIFT(inlink->h, desc->log2_chroma_h);
-    s->inplaneheight[0] = s->inplaneheight[3] = inlink->h;
-    s->inplanewidth[1]  = s->inplanewidth[2]  = FF_CEIL_RSHIFT(inlink->w, desc->log2_chroma_w);
-    s->inplanewidth[0]  = s->inplanewidth[3]  = inlink->w;
     s->nb_planes = av_pix_fmt_count_planes(inlink->format);
 
     if (desc->log2_chroma_h == desc->log2_chroma_w && desc->log2_chroma_h == 0) {
@@ -2409,9 +2478,9 @@ static int config_output(AVFilterLink *outlink)
 
     // Calculate remap data
     for (int p = 0; p < s->nb_allocated; p++) {
-        const int width = s->planewidth[p];
+        const int width = s->pr_width[p];
         const int uv_linesize = s->uv_linesize[p];
-        const int height = s->planeheight[p];
+        const int height = s->pr_height[p];
         const int in_width = s->inplanewidth[p];
         const int in_height = s->inplaneheight[p];
         float du, dv;



More information about the ffmpeg-cvslog mailing list